/*
* FaceCat的Swift框架
* 上海卷卷猫信息技术有限公司
*/

import Cocoa
import libxml2

/*
* 坐标结构
*/
class FCPoint{
    var x : Double //横坐标
    var y : Double //纵坐标
    var isNotEmpty : Bool //是否不为空
    init(x:Double, y:Double){
        self.x = x
        self.y = y
        self.isNotEmpty = true
    }
}

/*
* 大小结构
*/
class FCSize{
    var cx : Double //长
    var cy : Double //宽
    var isNotEmpty:Bool //是否不为空
    init(cx:Double, cy:Double){
        self.cx = cx
        self.cy = cy
        self.isNotEmpty = true
    }
}

/*
* 矩形结构
*/
class FCRect{
    var left : Double //左侧
    var top : Double //上侧
    var right : Double //右侧
    var bottom : Double //底部
    var isNotEmpty:Bool //是否不为空
    init(left:Double, top:Double, right:Double, bottom:Double){
        self.left = left
        self.top = top
        self.right = right
        self.bottom = bottom
        self.isNotEmpty = true
    }
}

/*
* 边距信息
*/
class FCPadding{
    var left : Double //左侧
    var top : Double //上侧
    var right : Double //右侧
    var bottom : Double //底部
    var isNotEmpty:Bool //是否不为空
    init(left:Double, top:Double, right:Double, bottom:Double){
        self.left = left
        self.top = top
        self.right = right
        self.bottom = bottom
        self.isNotEmpty = true
    }
}

/*
 * 字符转Float
 * str:字符
 */
func StringToFloat(str:String)->(CGFloat){
    let string = str
    var cgFloat:CGFloat = 0
    if let doubleValue = Double(string)
    {
        cgFloat = CGFloat(doubleValue)
    }
    return cgFloat
 }

/*
 * 字符转颜色
 * str:字符
 */
func stringToColor(str:String)->NSColor{
    if str.contains("rgb("){
        var newStr = str.replacingOccurrences(of: "rgb(", with: "")
        newStr = newStr.replacingOccurrences(of: ")", with: "")
        let strs = newStr.split(separator: ",")
        if strs.count >= 3{
            return NSColor.init(red:StringToFloat(str:String(strs[0])) / 255,
                                green:StringToFloat(str:String(strs[1])) / 255,
                                blue:StringToFloat(str:String(strs[2])) / 255, alpha: 1)
        }
    }else if str.contains("rgba("){
        var newStr = str.replacingOccurrences(of: "rgba(", with: "")
        newStr = newStr.replacingOccurrences(of: ")", with: "")
        let strs = newStr.split(separator: ",")
        if strs.count >= 4{
            return NSColor.init(red:StringToFloat(str:String(strs[0])) / 255,
                                green:StringToFloat(str:String(strs[1])) / 255,
                                blue:StringToFloat(str:String(strs[2])) / 255,
                                alpha:StringToFloat(str:String(strs[3])) / 255)
        }
    }
    return NSColor.init(red:255, green:255, blue:255, alpha:0)
}

/*
 * 获取系统毫秒数
 */
func getTickCount()->Int64{
    return Int64(Date().timeIntervalSince1970 * 1000)
}

/*
* 绘图结构
*/
class FCPaint : NSObject{
    var cancelClick = false //是否退出点击
    var context = NSGraphicsContext.current
    var defaultUIStyle = "light" //默认样式
    var dragBeginPoint = FCPoint(x:0, y:0) //拖动开始时的触摸位置
    var dragBeginRect = FCRect(left:0, top:0, right:0, bottom:0) //拖动开始时的区域
    var draggingView = [FCView]()  //正被拖动的控件
    var focusedView = [FCView]() //焦点视图
    var isDoubleClick:Bool = false; //是否双击
    var isNotEmpty:Bool = false //是否不为空
    var isPath = false //是否路径
    var moveTo = false //是否开始移动
    var offsetX:Double = 0 //横向偏移
    var offsetY:Double = 0 //纵向偏移
    var scaleFactorX:Double = 1 //横向缩放比例
    var scaleFactorY:Double = 1 //纵向缩放比例
    var size = FCSize(cx:0, cy:0) //大小
    var systemFont = "Heiti SC" //系统字体
    var resizeColumnState:Int = 0 //改变列宽度的状态
    var resizeColumnBeginWidth:Double = 0 //改变列宽度的起始值
    var resizeColumnIndex:Int = -1 //改变列宽度的索引
    var touchDownPoint = FCPoint(x:0, y:0)
    var touchDownView = [FCView]() //鼠标按下的视图
    var touchMoveView = [FCView]()//鼠标移动的视图
    var uiViews = [NSView]()  //正被拖动的控件
    var views = [FCView]() //子视图
    var wHeight:Double = 0 //视图高度
    var onPaint:(FCView, FCPaint, FCRect) ->Void = {
        (view:FCView, paint:FCPaint, clipRect:FCRect) -> () in
    }
    var onPaintBorder:(FCView, FCPaint, FCRect) ->Void = {
        (view:FCView, paint:FCPaint, clipRect:FCRect) -> () in
    }
    var onMouseDown:(FCView, FCPoint, Int, Int, Int) ->Void = {
        (view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) -> () in
    }
    var onMouseMove:(FCView, FCPoint, Int, Int, Int) ->Void = {
        (view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) -> () in
    }
    var onMouseUp:(FCView, FCPoint, Int, Int, Int) ->Void = {
        (view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) -> () in
    }
    var onMouseWheel:(FCView, FCPoint, Int, Int, Int) ->Void = {
        (view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) -> () in
    }
    var onMouseEnter:(FCView, FCPoint, Int, Int, Int) ->Void = {
        (view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) -> () in
    }
    var onMouseLeave:(FCView, FCPoint, Int, Int, Int) ->Void = {
        (view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) -> () in
    }
    var onKeyDown:(FCView, Int) ->Void = {
        (view:FCView, value:Int) -> () in
    }
    var onKeyUp:(FCView, Int) ->Void = {
        (view:FCView, value:Int) -> () in
    }
    var onClick:(FCView, Bool, FCPoint, Bool, FCPoint, Int) ->Void = {
        (view:FCView, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint, clicks:Int) -> () in
    }
    var onUpdateView:([FCView]) ->Void = {
        (uViews:[FCView]) -> () in
    }
    var onPaintGridCell:(FCGrid, FCGridRow, FCGridColumn, FCGridCell, FCPaint, Double, Double, Double, Double) ->Void = {
        (grid:FCGrid, row:FCGridRow, column:FCGridColumn, cell:FCGridCell, paint:FCPaint, left:Double, top:Double, right:Double, bottom:Double) -> () in
    }
    var onPaintGridColumn:(FCGrid, FCGridColumn, FCPaint, Double, Double, Double, Double) ->Void = {
        (grid:FCGrid, column:FCGridColumn, paint:FCPaint, left:Double, top:Double, right:Double, bottom:Double) -> () in
    }
    var onClickGridCell:(FCGrid, FCGridRow, FCGridColumn, FCGridCell, Bool, FCPoint, Bool, FCPoint, Int) ->Void = {
        (grid:FCGrid, row:FCGridRow, gridColumn:FCGridColumn, cell:FCGridCell, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint, clicks:Int) -> () in
    }
    var onClickGridColumn:(FCGrid, FCGridColumn, Bool, FCPoint, Bool, FCPoint, Int) ->Void = {
        (grid:FCGrid, gridColumn:FCGridColumn, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint, clicks:Int) -> () in
    }
    var onPaintTreeNode:(FCTree, FCTreeRow, FCTreeColumn, FCTreeNode, FCPaint, Double, Double, Double, Double) ->Void = {
        (tree:FCTree, row:FCTreeRow, column:FCTreeColumn, node:FCTreeNode, paint:FCPaint, left:Double, top:Double, right:Double, bottom:Double) -> () in
    }
    var onClickTreeNode:(FCTree, FCTreeNode, Bool, FCPoint, Bool, FCPoint, Int) ->Void = {
        (tree:FCTree, node:FCTreeNode, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint, clicks:Int) -> () in
    }
    var onPaintChartScale:(FCChart, FCPaint, FCRect) -> Void = {
        (chart:FCChart, paint:FCPaint, clipRect:FCRect) -> () in
    }
    var onPaintChartHScale:(FCChart, FCPaint, FCRect) -> Void = {
        (chart:FCChart, paint:FCPaint, clipRect:FCRect) -> () in
    }
    var onPaintChartStock:(FCChart, FCPaint, FCRect) -> Void = {
        (chart:FCChart, paint:FCPaint, clipRect:FCRect) -> () in
    }
    var onPaintChartPlot:(FCChart, FCPaint, FCRect) -> Void = {
        (chart:FCChart, paint:FCPaint, clipRect:FCRect) -> () in
    }
    var onPaintChartCrossLine:(FCChart, FCPaint, FCRect) -> Void = {
        (chart:FCChart, paint:FCPaint, clipRect:FCRect) -> () in
    }
    var onCalculateChartMaxMin:(FCChart) -> Void = {
        (chart:FCChart) -> () in
    }
    var onPaintCalendarDayButton:(FCCalendar, DayButton, FCPaint) -> Void = {
        (calendar:FCCalendar, dayButton:DayButton, paint:FCPaint) -> () in
    }
    var onPaintCalendarMonthButton:(FCCalendar, MonthButton, FCPaint) -> Void = {
        (calendar:FCCalendar, monthButton:MonthButton, paint:FCPaint) -> () in
    }
    var onPaintCalendarYearButton:(FCCalendar, YearButton, FCPaint) -> Void = {
        (calendar:FCCalendar, yearButton:YearButton, paint:FCPaint) -> () in
    }
    var onPaintCalendarHeadDiv:(FCCalendar, HeadDiv, FCPaint) -> Void = {
        (calendar:FCCalendar, headDiv:HeadDiv, paint:FCPaint) -> () in
    }
    var onInvalidate:(FCPaint) -> Void = {
        (paint:FCPaint) -> () in
    }
    var onInvalidateView:(FCView) -> Void = {
        (view:FCView) -> () in
    }
    var onRenderViews:([FCView],FCPaint,FCRect) ->Void = {
        (uViews:[FCView], paint:FCPaint, clipRect:FCRect) -> () in
    }
    var onContainsPoint:(FCView, FCPoint) ->Bool = {(view:FCView, mp:FCPoint) -> Bool in
        return false
    }
    var onInvoke:(FCView, NSObject) -> Void = {
        (view:FCView, args:NSObject)-> () in
    }
    var hasPaintEvent = false
    var hasPaintBorderEvent = false
    var hasMouseDownEvent = false
    var hasMouseMoveEvent = false
    var hasMouseUpEvent = false
    var hasMouseWheelEvent = false
    var hasMouseEnterEvent = false
    var hasMouseLeaveEvent = false
    var hasKeyDownEvent = false
    var hasKeyUpEvent = false
    var hasClickEvent = false
    var hasUpdateViewEvent = false
    var hasPaintGridCellEvent = false
    var hasPaintGridColumnEvent = false
    var hasClickGridCellEvent = false
    var hasClickGridColumnEvent = false
    var hasPaintTreeNodeEvent = false
    var hasClickTreeNodeEvent = false
    var hasPaintChartScaleEvent = false
    var hasPaintChartHScaleEvent = false
    var hasPaintChartStockEvent = false
    var hasPaintChartPlotEvent = false
    var hasPaintChartCrossLineEvent = false
    var hasCalculateChartMaxMinEvent = false
    var hasPaintCalendarDayButtonEvent = false
    var hasPaintCalendarMonthButtonEvent = false
    var hasPaintCalendarYearButtonEvent = false
    var hasPaintCalendarHeadDivEvent = false
    var hasInvalidateEvent = false
    var hasInvalidateViewEvent = false
    var hasRenderViewsEvent = false
    var hasContainsPointEvent = false;
    var hasInvokeEvent = false;
    func addPaintEvent(callBack:@escaping (FCView, FCPaint, FCRect)->Void){
        hasPaintEvent = true
        onPaint = callBack
    }
    func addPaintBorderEvent(callBack:@escaping(FCView, FCPaint, FCRect)->Void){
        hasPaintBorderEvent = true
        onPaintBorder = callBack
    }
    func addMouseDownEvent(callBack:@escaping(FCView, FCPoint, Int, Int, Int)->Void){
        hasMouseDownEvent = true
        onMouseDown = callBack
    }
    func addMouseMoveEvent(callBack:@escaping(FCView, FCPoint, Int, Int, Int)->Void){
        hasMouseMoveEvent = true
        onMouseMove = callBack
    }
    func addMouseUpEvent(callBack:@escaping(FCView, FCPoint, Int, Int, Int)->Void){
        hasMouseUpEvent = true
        onMouseUp = callBack
    }
    func addMouseWheelEvent(callBack:@escaping(FCView, FCPoint, Int, Int, Int)->Void){
        hasMouseWheelEvent = true
        onMouseWheel = callBack
    }
    func addMouseEnterEvent(callBack:@escaping(FCView, FCPoint, Int, Int, Int)->Void){
        hasMouseEnterEvent = true
        onMouseEnter = callBack
    }
    func addMouseLeaveEvent(callBack:@escaping(FCView, FCPoint, Int, Int, Int)->Void){
        hasMouseLeaveEvent = true
        onMouseLeave = callBack
    }
    func addKeyDownEvent(callBack:@escaping(FCView, Int)->Void){
        hasKeyDownEvent = true
        onKeyDown = callBack
    }
    func addKeyUpEvent(callBack:@escaping(FCView, Int)->Void){
        hasKeyUpEvent = true
        onKeyUp = callBack
    }
    func addClickEvent(callBack:@escaping(FCView, Bool, FCPoint, Bool, FCPoint, Int)->Void){
        hasClickEvent = true
        onClick = callBack
    }
    func addUpdateViewEvent(callBack:@escaping([FCView])->Void){
        hasUpdateViewEvent = true
        onUpdateView = callBack
    }
    func addPaintGridCellEvent(callBack:@escaping(FCGrid, FCGridRow, FCGridColumn, FCGridCell, FCPaint, Double, Double, Double, Double)->Void){
        hasPaintGridCellEvent = true
        onPaintGridCell = callBack
    }
    func addPaintGridColumnEvent(callBack:@escaping(FCGrid, FCGridColumn, FCPaint, Double, Double, Double, Double)->Void) {
        hasPaintGridColumnEvent = true
        onPaintGridColumn = callBack
    }
    func addClickGridCellEvent(callBack:@escaping(FCGrid, FCGridRow, FCGridColumn, FCGridCell, Bool, FCPoint, Bool, FCPoint, Int)->Void){
        hasClickGridCellEvent = true
        onClickGridCell = callBack
    }
    func addClickGridColumnEvent(callBack:@escaping(FCGrid, FCGridColumn, Bool, FCPoint, Bool, FCPoint, Int)->Void){
        hasClickGridColumnEvent = true
        onClickGridColumn = callBack
    }
    func addPaintTreeNodeEvent(callBack:@escaping(FCTree, FCTreeRow, FCTreeColumn, FCTreeNode, FCPaint, Double, Double, Double, Double)->Void){
        hasPaintTreeNodeEvent = true
        onPaintTreeNode = callBack
    }
    func addClickTreeNodeEvent(callBack:@escaping(FCTree, FCTreeNode, Bool, FCPoint, Bool, FCPoint, Int)->Void){
        hasClickTreeNodeEvent = true
        onClickTreeNode = callBack
    }
    func addPaintChartScaleEvent (callBack:@escaping(FCChart, FCPaint, FCRect)->Void){
        hasPaintChartScaleEvent = true
        onPaintChartScale = callBack
    }
    func addPaintChartHScaleEvent (callBack:@escaping(FCChart, FCPaint, FCRect)->Void){
        hasPaintChartHScaleEvent = true
        onPaintChartHScale = callBack
    }
    func addPaintChartStockEvent (callBack:@escaping(FCChart, FCPaint, FCRect)->Void){
        hasPaintChartStockEvent = true
        onPaintChartStock = callBack
    }
    func addPaintChartPlotEvent (callBack:@escaping(FCChart, FCPaint, FCRect)->Void){
        hasPaintChartPlotEvent = true
        onPaintChartPlot = callBack
    }
    func addPaintChartCrossLineEvent (callBack:@escaping(FCChart, FCPaint, FCRect)->Void){
        hasPaintChartCrossLineEvent = true
        onPaintChartCrossLine = callBack
    }
    func addCalculateChartMaxMinEvent (callBack:@escaping(FCChart)->Void){
        hasCalculateChartMaxMinEvent = true
        onCalculateChartMaxMin = callBack
    }
    func addPaintCalendarDayButtonEvent (callBack:@escaping(FCCalendar, DayButton, FCPaint)->Void){
        hasPaintCalendarDayButtonEvent = true
        onPaintCalendarDayButton = callBack
    }
    func addPaintCalendarMonthButtonEvent (callBack:@escaping(FCCalendar, MonthButton, FCPaint)->Void){
        hasPaintCalendarMonthButtonEvent = true
        onPaintCalendarMonthButton = callBack
    }
    func addPaintCalendarYearButtonEvent (callBack:@escaping(FCCalendar, YearButton, FCPaint)->Void){
        hasPaintCalendarYearButtonEvent = true
        onPaintCalendarYearButton = callBack
    }
    func addPaintCalendarHeadDivEvent (callBack:@escaping(FCCalendar, HeadDiv, FCPaint)->Void){
        hasPaintCalendarHeadDivEvent = true
        onPaintCalendarHeadDiv = callBack
    }
    func addInvalidateEvent (callBack:@escaping(FCPaint)->Void){
        hasInvalidateEvent = true
        onInvalidate = callBack
    }
    func addInvalidateViewEvent (callBack:@escaping(FCView)->Void){
        hasInvalidateViewEvent = true
        onInvalidateView = callBack
    }
    func addRenderViewsEvent (callBack:@escaping([FCView],FCPaint,FCRect)->Void){
        hasRenderViewsEvent = true
        onRenderViews = callBack
    }
    func addContainsPointEvent(callBack:@escaping(FCView,FCPoint)->Bool){
        hasContainsPointEvent = true
        onContainsPoint = callBack
    }
    func addInvokeEvent(callBack:@escaping(FCView,NSObject)->Void){
        hasInvokeEvent = true
        onInvoke = callBack
    }
    func getUIView()->NSView{
        if self.uiViews.count > 0{
            return self.uiViews[0]
        }else{
            let view = NSView.init()
            return view
        }
    }
    
    func setUIView(view:NSView){
        self.uiViews = [NSView]()
        self.uiViews.append(view)
    }
    func getTouchDownView()->FCView{
        if self.touchDownView.count > 0{
            return self.touchDownView[0]
        }else{
            let noneView = FCView()
            noneView.isNotEmpty = false
            return noneView
        }
    }
    
    func setTouchDownView(view:FCView){
        self.touchDownView = [FCView]()
        self.touchDownView.append(view)
    }
    
    func getTouchMoveView()->FCView{
        if self.touchMoveView.count > 0{
            return self.touchMoveView[0]
        }else{
            let noneView = FCView()
            noneView.isNotEmpty = false
            return noneView
        }
    }
    
    func setTouchMoveView(view:FCView){
        self.touchMoveView = [FCView]()
        self.touchMoveView.append(view)
    }
    
    func getFocusedView()->FCView{
        if self.focusedView.count > 0{
            return self.focusedView[0]
        }else{
            let noneView = FCView()
            noneView.isNotEmpty = false
            return noneView
        }
    }
    
    func setFocusedView(view:FCView){
        self.focusedView = [FCView]()
        self.focusedView.append(view)
    }
    
    func getDraggingView()->FCView{
        if self.draggingView.count > 0{
            return self.draggingView[0]
        }else{
            let noneView = FCView()
            noneView.isNotEmpty = false
            return noneView
        }
    }
    
    func setDraggingView(view:FCView){
        self.draggingView = [FCView]()
        self.draggingView.append(view)
    }

    /*
    * 添加线
    * x1:横坐标1
    * y1:纵坐标1
    * x2:横坐标2
    * y2:纵坐标2
    */
    func addLine(x1:Double, y1:Double, x2:Double, y2:Double){
        if !self.moveTo {
            self.moveTo = true
            self.context?.cgContext.move(to:CGPoint(x:(x1 + self.offsetX) * self.scaleFactorX, y:self.wHeight - (y1 + self.offsetY) * self.scaleFactorY))
        }
        self.context?.cgContext.addLine(to:CGPoint(x:(x2 + self.offsetX) * self.scaleFactorX, y:self.wHeight - (y2 + self.offsetY) * self.scaleFactorY))
    }
    /*
    * 开始路径
    */
    func beginPath(){
        self.moveTo = false
        self.isPath = true
        self.context?.cgContext.beginPath()
    }
    /*
    * 开始绘图
    * rect:区域
    */
    func beginPaint(rect:FCRect){
        self.context = NSGraphicsContext.current
        //self.context = UIGraphicsGetCurrentContext()
    }
    /*
    * 闭合路径
    */
    func closeFigure(){
        self.context?.cgContext.closePath()
    }
    /*
    * 关闭路径
    */
    func closePath(){
        self.moveTo = false
    }
    /*
    * 绘制线
    * color:颜色
    * width:宽度
    * style:样式
    * x1:横坐标1
    * y1:纵坐标1
    * x2:横坐标2
    * y2:纵坐标2
    */
    func drawLine(color:String, width:Double, style:[Double], x1:Double, y1:Double, x2:Double, y2:Double){
        self.context?.cgContext.move(to:CGPoint.init(x:(x1 + self.offsetX) * self.scaleFactorX, y:self.wHeight - (y1 + self.offsetY) * self.scaleFactorY))
        self.context?.cgContext.addLine(to:CGPoint.init(x:(x2 + self.offsetX) * self.scaleFactorX, y:self.wHeight - (y2 + self.offsetY) * self.scaleFactorY))
        self.context?.cgContext.setStrokeColor(stringToColor(str: color).cgColor)
        self.context?.cgContext.setLineWidth(CGFloat(width))
        if style.count > 0{
            var lengths = [CGFloat]()
            for i in 0...style.count - 1{
                lengths.append(CGFloat(style[i]))
            }
            self.context?.cgContext.setLineDash(phase: 0, lengths:lengths)
        }
        self.context?.cgContext.strokePath()
        if style.count > 0{
            self.context?.cgContext.setLineDash(phase: 0, lengths: [])
        }
    }
    /*
    * 绘制路径
    * color:颜色
    * width:宽度
    * style:样式
    */
    func drawPath(color:String, width:Double, style:[Double]){
        self.context?.cgContext.setStrokeColor(stringToColor(str: color).cgColor)
        self.context?.cgContext.setLineWidth(CGFloat(width))
        if style.count > 0{
            var lengths = [CGFloat]()
            for i in 0...style.count - 1{
                lengths.append(CGFloat(style[i]))
            }
            self.context?.cgContext.setLineDash(phase: 0, lengths:lengths)
        }
        self.context?.cgContext.strokePath()
        if style.count > 0{
            self.context?.cgContext.setLineDash(phase: 0, lengths: [])
        }
    }
    /*
    * 绘制连续线
    * color:颜色
    * width:宽度
    * style:样式
    * apt:坐标集合
    */
    func drawPolyline(color:String, width:Double, style:[Double], apt:[FCPoint]){
        if apt.count > 1{
            self.context?.cgContext.setStrokeColor(stringToColor(str: color).cgColor)
            self.context?.cgContext.setLineWidth(CGFloat(width))
            if style.count > 0{
                var lengths = [CGFloat]()
                for i in 0...style.count - 1{
                    lengths.append(CGFloat(style[i]))
                }
                self.context?.cgContext.setLineDash(phase: 0, lengths:lengths)
            }
            self.context?.cgContext.beginPath()
            for i in 0...apt.count - 1{
                var x = apt[i].x
                var y = apt[i].y
                x = x + self.offsetX
                y = y + self.offsetY
                if self.scaleFactorX != 1 || self.scaleFactorY != 1{
                    x = self.scaleFactorX * x
                    y = self.scaleFactorY * y
                }
                if i == 0{
                    self.context?.cgContext.move(to:CGPoint(x:x, y:self.wHeight - y))
                }else{
                    self.context?.cgContext.addLine(to:CGPoint(x:x, y:self.wHeight - y))
                }
            }
            self.context?.cgContext.closePath()
            self.context?.cgContext.strokePath()
            if style.count > 0{
                self.context?.cgContext.setLineDash(phase: 0, lengths: [])
            }
        }
    }
    /*
    * 绘制多边形
    * color:颜色
    * width:宽度
    * style:样式
    * apt:坐标集合
    */
    func drawPolygon(color:String, width:Double, style:[Double], apt:[FCPoint]){
        if apt.count > 1{
            self.context?.cgContext.setStrokeColor(stringToColor(str: color).cgColor)
            self.context?.cgContext.setLineWidth(CGFloat(width))
            if style.count > 0{
                var lengths = [CGFloat]()
                for i in 0...style.count - 1{
                    lengths.append(CGFloat(style[i]))
                }
                self.context?.cgContext.setLineDash(phase: 0, lengths:lengths)
            }
            self.context?.cgContext.beginPath()
            for i in 0...apt.count - 1{
                var x = apt[i].x
                var y = apt[i].y
                x = x + self.offsetX
                y = y + self.offsetY
                if self.scaleFactorX != 1 || self.scaleFactorY != 1{
                    x = self.scaleFactorX * x
                    y = self.scaleFactorY * y
                }
                if i == 0{
                    self.context?.cgContext.move(to:CGPoint(x:x, y:self.wHeight - y))
                }else{
                    self.context?.cgContext.addLine(to:CGPoint(x:x, y:self.wHeight - y))
                }
            }
            self.context?.cgContext.strokePath()
            if style.count > 0{
                self.context?.cgContext.setLineDash(phase: 0, lengths: [])
            }
        }
    }
    /*
    * 绘制矩形
    * color:颜色
    * width:宽度
    * style:样式
    * left:左侧坐标
    * top:上方坐标
    * right:右侧坐标
    * bottom:下方坐标
    */
    func drawRect(color:String, width:Double, style:[Double], left:Double, top:Double, right:Double, bottom:Double){
        let w = right - left
        let h = bottom - top
        self.context?.cgContext.addRect(CGRect(x: (left + self.offsetX) * self.scaleFactorX, y: self.wHeight - (top + self.offsetY) * self.scaleFactorY - h * self.scaleFactorY, width: w * self.scaleFactorX, height: h * self.scaleFactorY))
        self.context?.cgContext.setStrokeColor(stringToColor(str: color).cgColor)
        self.context?.cgContext.setLineWidth(CGFloat(width))
        if style.count > 0{
            var lengths = [CGFloat]()
            for i in 0...style.count - 1{
                lengths.append(CGFloat(style[i]))
            }
            self.context?.cgContext.setLineDash(phase: 0, lengths:lengths)
        }
        self.context?.cgContext.strokePath()
        if style.count > 0{
            self.context?.cgContext.setLineDash(phase: 0, lengths: [])
        }
    }
    /*
    * 绘制圆角矩形
    * color:颜色
    * width:宽度
    * style:样式
    * left:左侧坐标
    * top:上方坐标
    * right:右侧坐标
    * bottom:下方坐标
    * cornerRadius:圆角
    */
    func drawRoundRect(color:String, width:Double, style:[Double], left:Double, top:Double, right:Double, bottom:Double, cornerRadius:Double){
        if cornerRadius > 0{
            let w = right - left
            let h = bottom - top
            self.context?.cgContext.setStrokeColor(stringToColor(str: color).cgColor)
            self.context?.cgContext.setLineWidth(CGFloat(width))
            if style.count > 0{
                var lengths = [CGFloat]()
                for i in 0...style.count - 1{
                    lengths.append(CGFloat(style[i]))
                }
                self.context?.cgContext.setLineDash(phase: 0, lengths:lengths)
            }
            let path = NSBezierPath(roundedRect: CGRect(x: (left + self.offsetX) * self.scaleFactorX, y: self.wHeight - (top + self.offsetY) * self.scaleFactorY - h * self.scaleFactorY, width: w * self.scaleFactorX, height: h * self.scaleFactorY), xRadius: CGFloat(cornerRadius * min(self.scaleFactorX, self.scaleFactorY)), yRadius: CGFloat(cornerRadius * min(self.scaleFactorX, self.scaleFactorY)))
            path.stroke()
            if style.count > 0{
                self.context?.cgContext.setLineDash(phase: 0, lengths: [])
            }
        }else{
            drawRect(color:color, width:width, style:style, left:left, top:top, right:right, bottom:bottom)
        }
    }
    /*
    * 绘制图片
    * image:图片
    * left:左侧坐标
    * top:上方坐标
    * right:右侧坐标
    * bottom:下方坐标
    */
    func drawImage(image:String, left:Double, top:Double, right:Double, bottom:Double){
        let uiImage =  NSImage(contentsOfFile: image)
        let w = right - left
        let h = bottom - top
        uiImage?.draw(in: CGRect(x: (left + self.offsetX) * self.scaleFactorX, y: self.wHeight - (top + self.offsetY) * self.scaleFactorY - self.scaleFactorY, width: w * self.scaleFactorX, height: h * self.scaleFactorY))
    }
    /*
    * 绘制椭圆
    * color:颜色
    * width:宽度
    * style:样式
    * left:左侧坐标
    * top:上方坐标
    * right:右侧坐标
    * bottom:下方坐标
    */
    func drawEllipse(color:String, width:Double, style:[Double], left:Double, top:Double, right:Double, bottom:Double){
        let w = right - left
        let h = bottom - top
        self.context?.cgContext.addEllipse(in: CGRect(x: (left + self.offsetX) * self.scaleFactorX, y: self.wHeight - (top + self.offsetY) * self.scaleFactorY - h * self.scaleFactorY, width: w * self.scaleFactorX, height: h * self.scaleFactorY))
        self.context?.cgContext.setStrokeColor(stringToColor(str: color).cgColor)
        self.context?.cgContext.setLineWidth(CGFloat(width))
        if style.count > 0{
            var lengths = [CGFloat]()
            for i in 0...style.count - 1{
                lengths.append(CGFloat(style[i]))
            }
            self.context?.cgContext.setLineDash(phase: 0, lengths:lengths)
        }
        self.context?.cgContext.strokePath()
        if style.count > 0{
            self.context?.cgContext.setLineDash(phase: 0, lengths: [])
        }
    }
    /*
    * 绘制文字
    * text:文字
    * color:颜色
    * font:字体
    * x:横坐标
    * y:纵坐标
    */
    func drawText(text:String, color:String, font:String, x:Double, y:Double){
        let nsStr = text as NSString
        let strs = font.split(separator: ",")
        var fontName = String(strs[0])
        if fontName == "Default"{
            fontName = self.systemFont
        }
        var fontSize = StringToFloat(str: String(strs[1]))
        let textSize = self.textSize(text: text, font: font)
        fontSize = CGFloat((self.scaleFactorX + self.scaleFactorY) / 2.0) * fontSize
        let fontAttr = NSFont(name: fontName, size: fontSize)
        nsStr.draw(at: CGPoint(x: (x + self.offsetX) * self.scaleFactorX, y:self.wHeight - (y + self.offsetY) * self.scaleFactorY - textSize.cy * self.scaleFactorY), withAttributes: [NSAttributedString.Key.font : fontAttr!,NSAttributedString.Key.foregroundColor:stringToColor(str: color)])
    }
    /*
    * 结束绘图
    */
    func endPaint(){
        
    }
    /*
    * 填充路径
    * color:颜色
    */
    func fillPath(color:String){
        self.context?.cgContext.setFillColor(stringToColor(str: color).cgColor)
        self.context?.cgContext.fillPath()
    }
    /*
    * 填充多边形
    * color:颜色
    * apt:坐标集合
    */
    func fillPolygon(color:String, apt:[FCPoint]){
        if apt.count > 1{
            self.context?.cgContext.setFillColor(stringToColor(str: color).cgColor)
            self.context?.cgContext.beginPath()
            for i in 0...apt.count - 1{
                var x = apt[i].x
                var y = apt[i].y
                x = x + self.offsetX
                y = y + self.offsetY
                if self.scaleFactorX != 1 || self.scaleFactorY != 1{
                    x = self.scaleFactorX * x
                    y = self.scaleFactorY * y
                }
                if i == 0{
                    self.context?.cgContext.move(to:CGPoint(x:x, y:self.wHeight - y))
                }else{
                    self.context?.cgContext.addLine(to:CGPoint(x:x, y:self.wHeight - y))
                }
            }
            self.context?.cgContext.closePath()
            self.context?.cgContext.fillPath()
        }
    }
    /*
    * 填充矩形
    * color:颜色
    * left:左侧坐标
    * top:上方坐标
    * right:右侧坐标
    * bottom:下方坐标
    */
    func fillRect(color:String, left:Double, top:Double, right:Double, bottom:Double){
        let w = right - left
        let h = bottom - top
        self.context?.cgContext.setFillColor(stringToColor(str: color).cgColor)
        self.context?.cgContext.fill(CGRect(x: (left + self.offsetX) * self.scaleFactorX, y: self.wHeight - (top + self.offsetY) * self.scaleFactorY - h * self.scaleFactorY, width: w * self.scaleFactorX, height: h * self.scaleFactorY))
    }
    /*
    * 填充圆角矩形
    * color:颜色
    * left:左侧坐标
    * top:上方坐标
    * right:右侧坐标
    * bottom:下方坐标
    * cornerRadius:圆角
    */
    func fillRoundRect(color:String, left:Double, top:Double, right:Double, bottom:Double, cornerRadius:Double){
        if cornerRadius > 0{
            let w = right - left
            let h = bottom - top
            let path = NSBezierPath(roundedRect: CGRect(x: (left + self.offsetX) * self.scaleFactorX, y: self.wHeight - (top + self.offsetY) * self.scaleFactorY - h * self.scaleFactorY, width: w * self.scaleFactorX, height: h * self.scaleFactorY), xRadius: CGFloat(cornerRadius * min(self.scaleFactorX, self.scaleFactorY)), yRadius: CGFloat(cornerRadius * min(self.scaleFactorX, self.scaleFactorY)))
            self.context?.cgContext.setFillColor(stringToColor(str: color).cgColor)
            path.fill()
        }else{
            fillRect(color:color, left:left, top:top, right:right, bottom: bottom)
        }
    }
    /*
    * 填充椭圆
    * color:颜色
    * left:左侧坐标
    * top:上方坐标
    * right:右侧坐标
    * bottom:下方坐标
    */
    func fillEllipse(color:String, left:Double, top:Double, right:Double, bottom:Double){
        let w = right - left
        let h = bottom - top
        self.context?.cgContext.setFillColor(stringToColor(str: color).cgColor)
        self.context?.cgContext.fillEllipse(in: CGRect(x: (left + self.offsetX) * self.scaleFactorX, y: self.wHeight - (top + self.offsetY) * self.scaleFactorY - h * self.scaleFactorY, width: w * self.scaleFactorX, height: h * self.scaleFactorY))
    }
    /*
    * 裁剪
    * left:左侧坐标
    * top:上方坐标
    * right:右侧坐标
    * bottom:下方坐标
    */
    func setClip(left:Double, top:Double, right:Double, bottom:Double){
        let w = right - left
        let h = bottom - top
        self.context?.cgContext.clip(to: CGRect(x: (left + self.offsetX) * self.scaleFactorX, y: self.wHeight - (top + self.offsetY) * self.scaleFactorY - h * self.scaleFactorY, width: w * self.scaleFactorX, height: h * self.scaleFactorY))
    }
    /*
    * 设置偏移量
    * offsetX:横向偏移
    * offsetY:纵向偏移
    */
    func setOffset(x:Double, y:Double){
        self.offsetX = x
        self.offsetY = y
        
    }
    /*
    * 获取字体大小
    * text:文字
    * font:字体
    */
    func textSize(text:String, font:String)->FCSize{
        let nsStr = text as NSString
        let strs = font.split(separator: ",")
        var fontName = String(strs[0])
        if fontName == "Default"{
            fontName = self.systemFont
        }
        var fontSize = StringToFloat(str: String(strs[1]))
        let tRate = (self.scaleFactorX + self.scaleFactorY) / 2.0
        fontSize = CGFloat(tRate) * fontSize
        let fontAttr = NSFont(name: fontName, size: fontSize)
        let rect = nsStr.boundingRect(with: CGSize(width: 0, height: 0), options: [.usesFontLeading,.usesLineFragmentOrigin], attributes: [NSAttributedString.Key.font: fontAttr!], context: nil)
        let size = FCSize(cx:Double(rect.size.width / tRate), cy:Double(rect.size.height / tRate))
        return size
    }
    /*
    * 保存状态
    */
    func save(){
        self.context?.cgContext.saveGState()
    }
    /*
    * 恢复状态
    */
    func restore(){
        self.context?.cgContext.restoreGState()
    }
    /*
    * 绘制文字
    * text:文字
    * color:颜色
    * font:字体
    * left:左侧坐标
    * top:上方坐标
    * right:右侧坐标
    * bottom:下方坐标
    */
    func drawTextAutoEllipsis(text:String, color:String, font:String, left:Double, top:Double, right:Double, bottom:Double){
        if text.count > 0 {
            var tSize = textSize(text:text, font:font)
            if tSize.cx < right - left {
                drawText(text:text, color:color, font:font, x:left, y:top)
            } else {
                if tSize.cx > 0 {
                    var subLen = 3
                    while true {
                        let newLen = text.count - subLen
                        if newLen > 0 {
                            let newText = text.prefix(newLen) + "..."
                            tSize = textSize(text:String(newText), font:font)
                            if tSize.cx < right - left {
                                drawText(text:String(newText), color:color, font:font, x:left, y:top)
                                break
                            } else {
                                subLen += 3
                            }
                        } else {
                            break
                        }
                    }
                }
            }
        }
    }
}

/*
* 基础视图
*/
class FCView : NSObject{
    var align = "left" //横向布局
    var allowDrag = false //是否允许拖动
    var allowResize = false //是否可以拖动改变大小
    var allowDragScroll = false //是否允许拖动滚动
    var allowPreviewsEvent = false //是否允许预处理事件
    var backColor = "rgb(255,255,255)" //背景色
    var borderColor = "rgb(150,150,150)" //边线色
    var borderWidth:Double = 1 //边线宽度
    var clipRect = FCRect(left:0, top:0, right:0, bottom:0) //裁剪区域
    var cornerRadius = 0.0 //圆角
    var cursor = "" //光标
    var displayOffset = true //是否显示偏移量
    var dock = "none" //悬浮状态
    var downScrollHButton = false //是否按下横向滚动条
    var downScrollVButton = false //是否按下纵向滚动条
    var enabled = true //是否可用
    var exAttributes : [String : String] = [:] //额外属性
    var font = "Default,12" //字体
    var hoveredColor = "none" //鼠标悬停时的颜色
    var hoverScrollHButton = false //是否悬停横向滚动条
    var hoverScrollVButton = false //是否悬停纵向滚动条
    var hScrollIsVisible = false //横向滚动是否显示
    var isNotEmpty:Bool //是否不为空
    var location = FCPoint(x:0, y:0) //坐标
    var margin = FCPadding(left:0, top:0, right:0, bottom:0) //外边距
    var maximumSize: FCSize = FCSize(cx:0, cy:0) //大小
    var padding = FCPadding(left:0, top:0, right:0, bottom:0) //内边距
    var paintList = [FCPaint]() //绘图对象
    var parentList = [FCView]() //父视图
    var pushedColor = "rgb(100,100,100)" //鼠标按下时的颜色
    var resizePoint:Int = -1 //调整尺寸的点
    var scrollV:Double = 0 //纵向滚动
    var scrollH:Double = 0 //横向滚动
    var scrollSize:Double = 8 //滚动条的大小
    var showHScrollBar = false //是否显示横向滚动条
    var showVScrollBar = false //是否显示横向滚动条
    var scrollBarColor:String = "rgb(200,200,200)" //滚动条的颜色
    var scrollBarHoveredColor:String = "rgb(42,138,195)" //滚动条悬停的颜色
    var size = FCSize(cx:100, cy:20) //大小
    var startScrollH:Double = 0 //开始滚动的值
    var startScrollV:Double = 0 //结束滚动的值
    var startPoint = FCPoint(x:0, y:0) //起始点
    var startRect = FCRect(left:0, top:0, right:0, bottom:0) //移动开始时的视图矩形
    var tabIndex:Int = 0 //Tab索引
    var tabStop = false //是否支持Tab
    var text = "" //文字
    var textColor = "rgb(0,0,0)" //前景色
    var topMost = false //是否置顶
    var touchDownTime:Int64 = 0 //鼠标按下的时间
    var verticalAlign = "top" //纵向布局
    var viewName = "" //名称
    var viewType = "none" //类型
    var views = [FCView]() //子视图
    var visible = true //可见性
    var vScrollIsVisible = false //纵向滚动是否显示
    var onPaint:(FCView, FCPaint, FCRect) ->Void = {
        (view:FCView, paint:FCPaint, clipRect:FCRect) -> () in
    }
    var onPaintBorder:(FCView, FCPaint, FCRect) ->Void = {
        (view:FCView, paint:FCPaint, clipRect:FCRect) -> () in
    }
    var onMouseDown:(FCView, FCPoint, Int, Int, Int) ->Void = {
        (view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) -> () in
    }
    var onMouseMove:(FCView, FCPoint, Int, Int, Int) ->Void = {
        (view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) -> () in
    }
    var onMouseUp:(FCView, FCPoint, Int, Int, Int) ->Void = {
        (view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) -> () in
    }
    var onMouseWheel:(FCView, FCPoint, Int, Int, Int) ->Void = {
        (view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) -> () in
    }
    var onKeyDown:(FCView, Int) ->Void = {
        (view:FCView, value:Int) -> () in
    }
    var onKeyUp:(FCView, Int) ->Void = {
        (view:FCView, value:Int) -> () in
    }
    var onClick:(FCView, Bool, FCPoint, Bool, FCPoint, Int) ->Void = {
        (view:FCView, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint, clicks:Int) -> () in
    }
    var onMouseEnter:(FCView, FCPoint, Int, Int, Int) ->Void = {
        (view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) -> () in
    }
    var onMouseLeave:(FCView, FCPoint, Int, Int, Int) ->Void = {
        (view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) -> () in
    }
    var onInvoke:(FCView, NSObject) -> Void = {
        (view:FCView, args:NSObject)-> () in
    }
    var hasPaintEvent = false
    var hasPaintBorderEvent = false
    var hasMouseDownEvent = false
    var hasMouseMoveEvent = false
    var hasMouseUpEvent = false
    var hasMouseWheelEvent = false
    var hasKeyDownEvent = false
    var hasKeyUpEvent = false
    var hasClickEvent = false
    var hasMouseEnterEvent = false
    var hasMouseLeaveEvent = false
    var hasInvokeEvent = false;
    func addPaintEvent(callBack:@escaping (FCView, FCPaint, FCRect)->Void){
        hasPaintEvent = true
        onPaint = callBack
    }
    func addPaintBorderEvent(callBack:@escaping(FCView, FCPaint, FCRect)->Void){
        hasPaintBorderEvent = true
        onPaintBorder = callBack
    }
    func addMouseDownEvent(callBack:@escaping(FCView, FCPoint, Int, Int, Int)->Void){
        hasMouseDownEvent = true
        onMouseDown = callBack
    }
    func addMouseMoveEvent(callBack:@escaping(FCView, FCPoint, Int, Int, Int)->Void){
        hasMouseMoveEvent = true
        onMouseMove = callBack
    }
    func addMouseUpEvent(callBack:@escaping(FCView, FCPoint, Int, Int, Int)->Void){
        hasMouseUpEvent = true
        onMouseUp = callBack
    }
    func addMouseWheelEvent(callBack:@escaping(FCView, FCPoint, Int, Int, Int)->Void){
        hasMouseWheelEvent = true
        onMouseWheel = callBack
    }
    func addKeyDownEvent(callBack:@escaping(FCView, Int)->Void){
        hasKeyDownEvent = true
        onKeyDown = callBack
    }
    func addKeyUpEvent(callBack:@escaping(FCView, Int)->Void){
        hasKeyUpEvent = true
        onKeyUp = callBack
    }
    func addClickEvent(callBack:@escaping(FCView, Bool, FCPoint, Bool, FCPoint, Int)->Void){
        hasClickEvent = true
        onClick = callBack
    }
    func addMouseEnterEvent(callBack:@escaping(FCView, FCPoint, Int, Int, Int)->Void){
        hasMouseEnterEvent = true
        onMouseEnter = callBack
    }
    func addMouseLeaveEvent(callBack:@escaping(FCView, FCPoint, Int, Int, Int)->Void){
        hasMouseLeaveEvent = true
        onMouseLeave = callBack
    }
    func addInvokeEvent(callBack:@escaping(FCView,NSObject)->Void){
        hasInvokeEvent = true
        onInvoke = callBack
    }
    func getParent()->FCView{
        if self.parentList.count > 0{
            return self.parentList[0]
        }else{
            let noneView = FCView()
            noneView.isNotEmpty = false
            return noneView
        }
    }
    func setParent(parent:FCView){
        self.parentList = [FCView]()
        self.parentList.append(parent)
    }
    func getPaint()->FCPaint{
        if self.paintList.count > 0{
            return self.paintList[0]
        }else{
            let nonePaint = FCPaint()
            nonePaint.isNotEmpty = false
            return nonePaint
        }
    }
    func setPaint(paint:FCPaint){
        self.paintList = [FCPaint]()
        self.paintList.append(paint)
        
    }
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 按钮
*/
class FCButton:FCView{
    override init(){
        super.init()
        super.viewType = "button"
    }
}

/*
* 标签
*/
class FCLabel:FCView{
    override init(){
        super.init()
        super.viewType = "label"
    }
}

/*
* 文本框
*/
class FCTextBox:FCView{
    override init(){
        super.init()
        super.viewType = "textbox"
    }
}

/*
* 图层
*/
class FCDiv:FCView{
    var isScrolling = false //是否正在加速
    var scrollAddSpeed = 0//滚动加速
    var scrollDirection = 0 //滚动方向
    override init(){
        super.init()
        super.viewType = "div"
        super.allowDragScroll = true
        super.showHScrollBar = false
        super.showVScrollBar = false
    }
}

/*
* 页
*/
class FCTabPage:FCView{
    override init(){
        super.init()
        super.viewType = "tabpage"
        super.visible = false
    }
    var headerButton = [FCView]() //页头的按钮
    func getHeaderButton()->FCView{
        if self.headerButton.count > 0{
            return self.headerButton[0]
        }else{
            let noneView = FCView()
            noneView.isNotEmpty = false
            return noneView
        }
    }
    func setHeaderButton(view:FCView){
        self.headerButton = [FCView]()
        self.headerButton.append(view)
    }
}

/*
* 多页夹
*/
class FCTabView:FCView{
    override init(){
        super.init()
        super.viewType = "tabview"
    }
    var animationSpeed:Int = 20 //动画速度
    var layout = "top" //布局方式
    var tabPages = [FCTabPage]() //页夹集合
    var underLineColor = "none" //下划线的颜色
    var underLineSize:Double = 0 //下划线的宽度
    var underPoint = FCPoint(x:0, y:0) //下划点
    var useAnimation = false //是否使用动画
}

/*
* 复选按钮
*/
class FCCheckBox:FCView{
    override init(){
        super.init()
        super.viewType = "checkbox"
    }
    var buttonSize = FCSize(cx:16, cy:16)//按钮的大小
    var checked = false //是否选中
}

/*
 * 多布局图层
 */
class FCLayoutDiv:FCDiv{
    override init(){
        super.init()
        super.viewType = "layout"
    }
    var autoWrap = false //是否自动换行
    var layoutStyle = "lefttoright" //分割方式
}

/*
* 分割图层
*/
class FCSplitLayoutDiv:FCView{
    override init(){
        super.init()
        super.viewType = "split"
    }
    var firstView = [FCView]() //第一个视图
    var layoutStyle = "lefttoright" //分割方式
    var oldSize = FCSize(cx:0, cy:0) //上次的尺寸
    var secondView = [FCView]() //第二个视图
    var splitMode = "absolutesize" //分割模式 percentsize百分比或absolutesize绝对值
    var splitPercent:Double = -1 //分割百分比
    var splitter = [FCView]() //分割线
    func getFirstView()->FCView{
        if self.firstView.count > 0{
            return self.firstView[0]
        }else{
            let noneView = FCView()
            noneView.isNotEmpty = false
            return noneView
        }
    }
    func setFirstView(view:FCView){
        self.firstView = [FCView]()
        self.firstView.append(view)
    }
    func getSecondView()->FCView{
        if self.secondView.count > 0{
            return self.secondView[0]
        }else{
            let noneView = FCView()
            noneView.isNotEmpty = false
            return noneView
        }
    }
    func setSecondView(view:FCView){
        self.secondView = [FCView]()
        self.secondView.append(view)
    }
    func getSplitter()->FCView{
        if self.splitter.count > 0{
            return self.splitter[0]
        }else{
            let noneView = FCView()
            noneView.isNotEmpty = false
            return noneView
        }
    }
    func setSplitter(view:FCView){
        self.splitter = [FCView]()
        self.splitter.append(view)
    }
}

/*
* 单选按钮
*/
class FCRadioButton:FCView{
    override init(){
        super.init()
        super.viewType = "radiobutton"
    }
    var buttonSize = FCSize(cx:16, cy:16)//按钮的大小
    var checked = false //是否选中
    var groupName = "" //组别
}

/*
* 表格列
*/
class FCGridColumn:NSObject{
    var allowResize = false //是否允许改变大小
    var allowSort = true //是否允许排序
    var backColor = "rgb(200,200,200)" //背景色
    var borderColor = "rgb(150,150,150)" //边线颜色
    var bounds = FCRect(left:0, top:0, right:0, bottom:0) //区域
    var cellAlign = "left" //left:居左 center:居中 right:居右
    var colName = "" //名称
    var colType = "" //类型 string:字符串 double:浮点型 int:整型 bool:布尔型
    var font = "Default,14" //字体
    var frozen = false //是否冻结
    var index:Int = -1 //索引
    var isNotEmpty:Bool
    var sort = "none" //排序模式
    var text = "" //文字
    var textColor = "rgb(50,50,50)" //文字颜色
    var visible = true //是否可见
    var width:Double = 120 //宽度
    var widthStr = "" //特殊宽度
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 表格单元格
*/
class FCGridCell:NSObject{
    var backColor = "rgb(255,255,255)" //背景色
    var borderColor = "rgb(150,150,150)" //边线色
    var colSpan:Int = 1 //列距
    var column = [FCGridColumn]() //所在列
    var digit = -1 //保留小数的位数
    var font = "Default,14" //字体
    var isNotEmpty:Bool
    var row = [FCGridRow]() //所在行
    var rowSpan:Int = 1 //行距
    var textColor = "rgb(0,0,0)" //前景色
    var value = "" //值
    var view = [FCView]() //包含的视图
    override init(){
        self.isNotEmpty = true
    }
    func getColumn()->FCGridColumn{
        if self.column.count > 0{
            return self.column[0]
        }else{
            let noneColumn = FCGridColumn()
            noneColumn.isNotEmpty = false
            return noneColumn
        }
    }
    func setColumn(col:FCGridColumn){
        self.column = [FCGridColumn]()
        self.column.append(col)
    }
    func getRow()->FCGridRow{
        if self.row.count > 0{
            return self.row[0]
        }else{
            let noneRow = FCGridRow()
            noneRow.isNotEmpty = false
            return noneRow
        }
    }
    func setRow(r:FCGridRow){
        self.row = [FCGridRow]()
        self.row.append(r)
    }
    func getView()->FCView{
        if self.view.count > 0{
            return self.view[0]
        }else{
            let noneView = FCView()
            noneView.isNotEmpty = false
            return noneView
        }
    }
    func setView(v:FCView){
        self.view = [FCView]()
        self.view.append(v)
    }
}

/*
* 表格行
*/
class FCGridRow:NSObject{
    var cells = [FCGridCell]() //单元格
    var index:Int = -1
    var key = "" //排序键值
    var isNotEmpty:Bool
    var selected = false //是否选中
    var sortColIndex = -1 //当前排序的列
    var visible = true //是否可见
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 表格
*/
class FCGrid:FCView{
    var columns = [FCGridColumn]() //所有的列
    var headerHeight:Double = 30 //头部高度
    var isScrolling = false //是否正在滚动
    var rows = [FCGridRow]() //包含的所有行
    var rowHeight:Double = 30 //行高
    var seletedRowColor = "rgb(125,125,125)" //选中行的颜色
    var selectedRowColor = "rgb(125,125,125)" //选中行的颜色
    var scrollAddSpeed = 0//滚动加速
    var scrollDirection = 0 //滚动方向
    var onPaintGridCell:(FCGrid, FCGridRow, FCGridColumn, FCGridCell, FCPaint, Double, Double, Double, Double) ->Void = {
        (grid:FCGrid, row:FCGridRow, column:FCGridColumn, cell:FCGridCell, paint:FCPaint, left:Double, top:Double, right:Double, bottom:Double) -> () in
    }
    var onPaintGridColumn:(FCGrid, FCGridColumn, FCPaint, Double, Double, Double, Double) ->Void = {
        (grid:FCGrid, column:FCGridColumn, paint:FCPaint, left:Double, top:Double, right:Double, bottom:Double) -> () in
    }
    var onClickGridCell:(FCGrid, FCGridRow, FCGridColumn, FCGridCell, Bool, FCPoint, Bool, FCPoint, Int) ->Void = {
        (grid:FCGrid, row:FCGridRow, gridColumn:FCGridColumn, cell:FCGridCell, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint, clicks:Int) -> () in
    }
    var onClickGridColumn:(FCGrid, FCGridColumn, Bool, FCPoint, Bool, FCPoint, Int) ->Void = {
        (grid:FCGrid, gridColumn:FCGridColumn, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint, clicks:Int) -> () in
    }
    var hasPaintGridCellEvent = false
    var hasPaintGridColumnEvent = false
    var hasClickGridCellEvent = false
    var hasClickGridColumnEvent = false
    func addPaintGridCellEvent(callBack:@escaping(FCGrid, FCGridRow, FCGridColumn, FCGridCell, FCPaint, Double, Double, Double, Double)->Void){
        hasPaintGridCellEvent = true
        onPaintGridCell = callBack
    }
    func addPaintGridColumnEvent(callBack:@escaping(FCGrid, FCGridColumn, FCPaint, Double, Double, Double, Double)->Void) {
        hasPaintGridColumnEvent = true
        onPaintGridColumn = callBack
    }
    func addClickGridCellEvent(callBack:@escaping(FCGrid, FCGridRow, FCGridColumn, FCGridCell, Bool, FCPoint, Bool, FCPoint, Int)->Void){
        hasClickGridCellEvent = true
        onClickGridCell = callBack
    }
    func addClickGridColumnEvent(callBack:@escaping(FCGrid, FCGridColumn, Bool, FCPoint, Bool, FCPoint, Int)->Void){
        hasClickGridColumnEvent = true
        onClickGridColumn = callBack
    }
    override init(){
        super.init()
        super.viewType = "grid"
        super.allowDragScroll = true
        super.showHScrollBar = true
        super.showVScrollBar = true
    }
}

/*
* 树的列
*/
class FCTreeColumn:NSObject{
    var bounds = FCRect(left:0, top:0, right:0, bottom:0) //区域
    var index:Int = -1 //索引
    var isNotEmpty = false
    var visible = true //是否可见
    var width:Double = 120 //宽度
    var widthStr = "" //特殊宽度
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 树的行
*/
class FCTreeRow:NSObject{
    var cells = [FCTreeNode]() //单元格
    var index:Int = -1 //索引
    var isNotEmpty = false
    var selected = false //是否选中
    var visible = true //是否可见
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 树节点
*/
class FCTreeNode:NSObject{
    var allowCollapsed = true //是否允许折叠
    var backColor = "rgb(255,255,255)" //背景色
    var checked = false //是否选中
    var childNodes = [FCTreeNode]() //子节点
    var collapsed = false //是否折叠
    var column = [FCTreeColumn]() //所有的列
    var font = "Default,14" //字体
    var indent:Double = 0 //缩进
    var isNotEmpty = false
    var parentNode = [FCTreeNode]()
    var row = [FCTreeRow]() //包含的所有行
    var textColor = "rgb(0,0,0)" //前景色
    var value = "" //值
    override init(){
        self.isNotEmpty = true
    }
    func getColumn()->FCTreeColumn{
        if self.column.count > 0{
            return self.column[0]
        }else{
            let noneColumn = FCTreeColumn()
            noneColumn.isNotEmpty = false
            return noneColumn
        }
    }
    func setColumn(col:FCTreeColumn){
        self.column = [FCTreeColumn]()
        self.column.append(col)
    }
    func getRow()->FCTreeRow{
        if(self.row.count > 0){
            return self.row[0]
        }else{
            let noneRow = FCTreeRow()
            noneRow.isNotEmpty = false
            return noneRow
        }
    }
    func setRow(r:FCTreeRow){
        self.row = [FCTreeRow]()
        self.row.append(r)
    }
    func getParentNode()->FCTreeNode{
        if self.parentNode.count > 0{
            return self.parentNode[0]
        }else{
            let noneNode = FCTreeNode()
            noneNode.isNotEmpty = false
            return noneNode
        }
    }
    func setParentNode(node:FCTreeNode){
        self.parentNode = [FCTreeNode]()
        self.parentNode.append(node)
    }
}

/*
* 树
*/
class FCTree:FCView{
    var checkBoxWidth:Double = 25 //复选框占用的宽度
    var collapsedWidth:Double = 25 //折叠按钮占用的宽度
    var childNodes = [FCTreeNode]() //子节点
    var columns = [FCTreeColumn]() //所有的列
    var headerHeight:Double = 0 //头部高度
    var indent:Double = 20 //缩进
    var isScrolling = false //是否正在滚动
    var rows = [FCTreeRow]() //包含的所有行
    var rowHeight:Double = 30 //行高
    var showCheckBox = false //是否显示复选框
    var scrollAddSpeed = 0 //滚动加速
    var scrollDirection = 0 //滚动方向
    var onPaintTreeNode:(FCTree, FCTreeRow, FCTreeColumn, FCTreeNode, FCPaint, Double, Double, Double, Double) ->Void = {
        (tree:FCTree, row:FCTreeRow, column:FCTreeColumn, node:FCTreeNode, paint:FCPaint, left:Double, top:Double, right:Double, bottom:Double) -> () in
    }
    var onClickTreeNode:(FCTree, FCTreeNode, Bool, FCPoint, Bool, FCPoint, Int) ->Void = {
        (tree:FCTree, node:FCTreeNode, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint, clicks:Int) -> () in
    }
    var hasPaintTreeNodeEvent = false
    var hasClickTreeNodeEvent = false
    func addPaintTreeNodeEvent(callBack:@escaping(FCTree, FCTreeRow, FCTreeColumn, FCTreeNode, FCPaint, Double, Double, Double, Double)->Void){
        hasPaintTreeNodeEvent = true
        onPaintTreeNode = callBack
    }
    func addClickTreeNodeEvent(callBack:@escaping(FCTree, FCTreeNode, Bool, FCPoint, Bool, FCPoint, Int)->Void){
        hasClickTreeNodeEvent = true
        onClickTreeNode = callBack
    }
    override init(){
        super.init()
        super.viewType = "tree"
        super.allowDragScroll = true
        super.showHScrollBar = true
        super.showVScrollBar = true
    }
}

/*
* 证券数据结构
*/
struct SecurityData{
    var amount:Double = 0 //成交额
    var close:Double = 0 //收盘价
    var date:Double = 0 //日期，为1970年到现在的秒
    var high:Double = 0 //最高价
    var low:Double = 0 //最低价
    var open:Double = 0 //开盘价
    var volume:Double = 0 //成交额
}

/*
* 基础图形
*/
class BaseShape:NSObject{
    var color = "none" //颜色
    var color2 = "none" //颜色2
    var datas = [Double]() //第一组数据
    var datas2 = [Double]() //第二组数据
    var divIndex:Int = 0 //所在层
    var leftOrRight = true //依附于左轴或右轴
    var isNotEmpty = false
    var lineWidth:Double = 1 //线的宽度
    var shapeName = "" //名称
    var shapeType = "line" //类型
    var showHideDatas = [Double]() //控制显示隐藏的数据
    var style = "" //样式
    var text = "" //显示的文字
    var title = "" //第一个标题
    var title2 = "" //第二个标题
    var value:Double = 0 //显示文字的值
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 画线工具结构
*/
class FCPlot:NSObject{
    var isNotEmpty = false
    var lineColor = "rgb(0,0,0)" //线的颜色
    var lineWidth:Double = 1 //线的宽度
    var key1:Double = 0 //第一个键
    var key2:Double = 0 //第二个键
    var key3:Double = 0 //第三个键
    var plotType = "Line" //线的类型
    var pointColor = "rgba(0,0,0,120)" //线的颜色
    var startKey1:Double = 0 //移动前第一个键
    var startValue1:Double = 0 //移动前第一个值
    var startKey2:Double = 0 //移动前第二个键
    var startValue2:Double = 0 //移动前第二个值
    var startKey3:Double = 0 //移动前第三个键
    var startValue3:Double = 0 //移动前第三个值
    var value1:Double = 0 //第一个值
    var value2:Double = 0 //第二个值
    var value3:Double = 0 //第三个值
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 图表
*/
class FCChart:FCView{
    var addingPlotChart = ""
    var allowDragChartDiv = false //是否允许拖拽图层
    var autoFillHScale = false //是否填充满X轴
    var candleDistance:Double = 0 //蜡烛线的距离
    var crossTipColor = "rgb(50,50,50)" //十字线标识的颜色
    var crossLineColor = "rgb(100,100,100)" //十字线的颜色
    var cycle = "second" //周期
    var candleMax:Double = 0 //蜡烛线的最大值
    var candleMin:Double = 0 //蜡烛线的最小值
    var candleMaxRight:Double = 0 //蜡烛线的右轴最大值
    var candleMinRight:Double = 0 //蜡烛线的右轴最小值
    var candleDigit:Int = 2 //图表层保留小数的位数
    var candleDivPercent:Double = 0.5 //图表层的占比
    var candlePaddingTop:Double = 30 //图表层的上边距
    var candlePaddingBottom:Double = 30 //图表层的下边距
    var crossStopIndex:Int = -1 //鼠标停留位置
    var data = [SecurityData]() //子节点
    var downColor = "rgb(15,193,118)" //下跌颜色
    var firstVisibleIndex:Int = -1 //起始可见的索引
    var gridColor = "rgba(255,0,0,120)" //网格颜色
    var hScaleHeight:Double = 30 //X轴的高度
    var hScalePixel:Double = 11 //蜡烛线的宽度
    var hScaleTextDistance:Double = 10 //X轴的文字间隔
    var hScaleFormat = "" //X轴的格式化字符，例如YYYY-mm-dd HH:MM:SS
    var indMax:Double = 0 //指标层的最大值
    var indMin:Double = 0 //指标的最小值
    var indMax2:Double = 0 //指标层2的最大值
    var indMin2:Double = 0 //指标层2的最小值
    var indMaxRight:Double = 0 //指标层的右轴最大值
    var indMinRight:Double = 0 //指标层的右轴最小值
    var indMax2Right:Double = 0 //指标层2的右轴最大值
    var indMin2Right:Double = 0 //指标层2的右轴最小值
    var indDigit:Int = 2 //指标层保留小数的位数
    var indDigit2:Int = 2 //指标层2保留小数的位数
    var indDivPercent:Double = 0.3 //指标层的占比
    var indDivPercent2:Double = 0.0 //指标层2的占比
    var indPaddingTop:Double = 20 //指标层的上边距
    var indPaddingBottom:Double = 20 //指标层的下边距
    var indPaddingTop2:Double = 20 //指标层2的上边距
    var indPaddingBottom2:Double = 20 //指标层2的下边距
    var indicatorColors = [String]() //扩展图形
    var lastRecordIsVisible = true //最后记录是否可见
    var lastVisibleKey:Double = 0 //最后可见的主键
    var lastVisibleIndex:Int = -1 //结束可见的索引
    var leftVScaleWidth:Double = 80 //左轴宽度
    var lastValidIndex:Int = -1 //最后有效数据索引
    var lineWidthChart:Double = 1
    var mainIndicator = "" //主图指标
    var magnitude:Int = 1 //成交量的比例
    var midColor = "none" //中间色
    var offsetX:Double = 0; //横向绘图偏移
    var plots = [FCPlot]() //画线
    var plotPointSizeChart:Double = 20 //画线的选中点大小
    var rightVScaleWidth:Double = 0 //右轴宽度
    var rightSpace:Double = 0 //右侧空间
    var scaleColor = "rgb(255,0,0)" //刻度的颜色
    var showIndicator = "" //显示指标
    var showCrossLine = false //是否显示十字线
    var selectPlotPoint:Int = -1 //选中画线的点
    var startMovePlot = false //选中画线
    var selectShape = "" //选中的图形
    var selectShapeEx = "" //选中的图形信息
    var shapes = [BaseShape]() //扩展图形
    var sPlot = [FCPlot]() //选中的线条
    var targetOldX: Double = 0; //缩小时旧的位置1
    var targetOldX2: Double = 0; //放大时旧的位置2
    var touchPosition = FCPoint(x:0, y:0) //鼠标坐标
    var touchDownPointChart = FCPoint(x:0,y:0)
    var volMax:Double = 0 //成交量层的最大值
    var volMin:Double = 0 //成交量层的最小值
    var volMaxRight:Double = 0 //成交量层的右轴最大值
    var volMinRight:Double = 0 //成交量层的右轴最小值
    var volDigit:Int = 0 //成交量层保留小数的位数
    var volDivPercent:Double = 0.2 //成交量层的占比
    var volPaddingTop:Double = 20 //成交量层的上边距
    var volPaddingBottom:Double = 0 //成交量层的下边距
    var vScaleDistance:Double = 35 //纵轴的间隔
    var vScaleType = "standard" //纵轴的类型 log10代表指数坐标
    var upColor = "rgb(219,68,83)" //上涨颜色
    var kChart:Double = 0
    var bChart:Double = 0
    var oXChart:Double = 0
    var oYChart:Double = 0
    var rChart:Double = 0
    var gridStepChart:Double = 0 //网格计算临时变量
    var gridDigitChart:Int = 0 //网格计算临时变量
    //拖动滚动的缓存
    var firstIndexCacheChart:Int = -1
    var firstTouchIndexCacheChart:Int = -1
    var firstTouchPointCacheChart = FCPoint(x:0, y:0)
    var lastIndexCacheChart:Int = -1
    var secondTouchIndexCacheChart:Int = -1
    var secondTouchPointCacheChart = FCPoint(x:0, y:0)
    var firstPaddingTop:Double = 0
    var firtstPaddingBottom:Double = 0
    var x4Chart:Double = 0
    var y4Chart:Double = 0
    var nHighChart:Double = 0
    var nLowChart:Double = 0
    var xChart:Double = 0
    var yChart:Double = 0
    var wChart:Double = 0
    var hChart:Double = 0
    var upSubValue:Double = 0
    var downSubValue:Double = 0
    var candleStyle = "rect"
    var barStyle = "rect"
    var firstOpen:Double = 0
    var allema12 = [Double]()
    var allema26 = [Double]()
    var alldifarr = [Double]()
    var alldeaarr = [Double]()
    var allmacdarr = [Double]()
    var bollUp = [Double]()
    var bollDown = [Double]()
    var bollMid = [Double]()
    var bias1 = [Double]()
    var bias2 = [Double]()
    var bias3 = [Double]()
    var kdjK = [Double]()
    var kdjD = [Double]()
    var kdjJ = [Double]()
    var rsi1 = [Double]()
    var rsi2 = [Double]()
    var rsi3 = [Double]()
    var roc = [Double]()
    var rocMa = [Double]()
    var wr1 = [Double]()
    var wr2 = [Double]()
    var cci = [Double]()
    var bbi = [Double]()
    var trix = [Double]()
    var trixMa = [Double]()
    var dma1 = [Double]()
    var dma2 = [Double]()
    var ma5 = [Double]()
    var ma10 = [Double]()
    var ma20 = [Double]()
    var ma30 = [Double]()
    var ma120 = [Double]()
    var ma250 = [Double]()
    var closeArr = [Double]()
    var onPaintChartScale:(FCChart, FCPaint, FCRect) -> Void = {
        (chart:FCChart, paint:FCPaint, clipRect:FCRect) -> () in
    }
    var onPaintChartHScale:(FCChart, FCPaint, FCRect) -> Void = {
        (chart:FCChart, paint:FCPaint, clipRect:FCRect) -> () in
    }
    var onPaintChartStock:(FCChart, FCPaint, FCRect) -> Void = {
        (chart:FCChart, paint:FCPaint, clipRect:FCRect) -> () in
    }
    var onPaintChartPlot:(FCChart, FCPaint, FCRect) -> Void = {
        (chart:FCChart, paint:FCPaint, clipRect:FCRect) -> () in
    }
    var onPaintChartCrossLine:(FCChart, FCPaint, FCRect) -> Void = {
        (chart:FCChart, paint:FCPaint, clipRect:FCRect) -> () in
    }
    var onCalculateChartMaxMin:(FCChart) -> Void = {
        (chart:FCChart) -> () in
    }
    var hasPaintChartScaleEvent = false
    var hasPaintChartHScaleEvent = false
    var hasPaintChartStockEvent = false
    var hasPaintChartPlotEvent = false
    var hasPaintChartCrossLineEvent = false
    var hasCalculateChartMaxMinEvent = false
    func addPaintChartScaleEvent (callBack:@escaping(FCChart, FCPaint, FCRect)->Void){
        hasPaintChartScaleEvent = true
        onPaintChartScale = callBack
    }
    func addPaintChartHScaleEvent (callBack:@escaping(FCChart, FCPaint, FCRect)->Void){
        hasPaintChartHScaleEvent = true
        onPaintChartHScale = callBack
    }
    func addPaintChartStockEvent (callBack:@escaping(FCChart, FCPaint, FCRect)->Void){
        hasPaintChartStockEvent = true
        onPaintChartStock = callBack
    }
    func addPaintChartPlotEvent (callBack:@escaping(FCChart, FCPaint, FCRect)->Void){
        hasPaintChartPlotEvent = true
        onPaintChartPlot = callBack
    }
    func addPaintChartCrossLineEvent (callBack:@escaping(FCChart, FCPaint, FCRect)->Void){
        hasPaintChartCrossLineEvent = true
        onPaintChartCrossLine = callBack
    }
    func addCalculateChartMaxMinEvent (callBack:@escaping(FCChart)->Void){
        hasCalculateChartMaxMinEvent = true
        onCalculateChartMaxMin = callBack
    }
    override init(){
        super.init()
        super.viewType = "chart"
        indicatorColors.append("rgb(100,100,100)")
        indicatorColors.append("rgb(206,147,27)")
        indicatorColors.append("rgb(150,0,150)")
        indicatorColors.append("rgb(255,0,0)")
        indicatorColors.append("rgb(0,150,150)")
        indicatorColors.append("rgb(0,150,0)")
        indicatorColors.append("rgb(59,174,218)")
        indicatorColors.append("rgb(50,50,50)")
        super.allowDragScroll = true
    }
    func getSelectedPlot()->FCPlot{
        if self.sPlot.count > 0{
            return self.sPlot[0]
        }else{
            let nonePlot = FCPlot()
            nonePlot.isNotEmpty = false
            return nonePlot
        }
    }
    func setSelectedPlot(plot:FCPlot){
        self.sPlot = [FCPlot]()
        self.sPlot.append(plot)
    }
}

/*
* 月层
*/
class MonthDiv:NSObject{
    var aDirection:Int = 0 //动画的方向
    var aTick:Int = 0 //动画当前帧数
    var aTotalTick:Int = 40 //动画总帧数
    var isNotEmpty = false
    var month:Int = 0 //月份
    var monthButtons = [MonthButton]() //月的按钮
    var monthButtonsAm = [MonthButton]() //动画日期的集合
    var year:Int = 0 //年份
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 年层
*/
class YearDiv:NSObject{
    var aDirection:Int = 0 //动画的方向
    var aTick:Int = 0 //动画当前帧数
    var aTotalTick:Int = 40 //动画总帧数
    var isNotEmpty = false
    var startYear:Int = 0 //开始年份
    var yearButtons = [YearButton]() //年的按钮
    var yearButtonsAm = [YearButton]() //动画日期的集合
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 头部层
*/
class HeadDiv:NSObject{
    var arrowColor = "rgb(150,150,150)" //箭头颜色
    var backColor = "rgb(255,255,255)" //箭头颜色
    var bounds = FCRect(left:0, top:0, right:0, bottom:0) //显示区域
    var isNotEmpty = false
    var textColor = "rgb(0,0,0)" //文字颜色
    var titleFont = "Default,20" //标题字体
    var weekFont = "Default,14" //星期字体
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 时间层
*/
class TimeDiv:NSObject{
    var bounds = FCRect(left:0, top:0, right:0, bottom:0) //显示区域
    var isNotEmpty = false
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 年的结构
*/
class CYear:NSObject{
    var isNotEmpty = false
    var months : [Int : CMonth] = [:] //月的集合
    var year:Int = 0 //年
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 月的结构
*/
class CMonth:NSObject{
    var days : [Int : CDay] = [:] //日的集合
    var isNotEmpty = false
    var month:Int = 0 //月
    var year:Int = 0 //年
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 日的结构
*/
class CDay:NSObject{
    var day:Int = 0 //日
    var isNotEmpty = false
    var month:Int = 0 //月
    var year:Int = 0 //年
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 日历
*/
class FCCalendar:FCView{
    var dayDiv = [DayDiv]() //日层
    var headDiv = [HeadDiv]() //头部层
    var mode = "day" //模式
    var monthDiv = [MonthDiv]() //月层
    var selectedDay = [CDay]() //选中日
    var timeDiv = [TimeDiv]() //时间层
    var useAnimation = false //是否使用动画
    var yearDiv = [YearDiv]() //年层
    var years : [Int : CYear] = [:] //日历
    var onPaintCalendarDayButton:(FCCalendar, DayButton, FCPaint) -> Void = {
        (calendar:FCCalendar, dayButton:DayButton, paint:FCPaint) -> () in
    }
    var onPaintCalendarMonthButton:(FCCalendar, MonthButton, FCPaint) -> Void = {
        (calendar:FCCalendar, monthButton:MonthButton, paint:FCPaint) -> () in
    }
    var onPaintCalendarYearButton:(FCCalendar, YearButton, FCPaint) -> Void = {
        (calendar:FCCalendar, yearButton:YearButton, paint:FCPaint) -> () in
    }
    var onPaintCalendarHeadDiv:(FCCalendar, HeadDiv, FCPaint) -> Void = {
        (calendar:FCCalendar, headDiv:HeadDiv, paint:FCPaint) -> () in
    }
    var hasPaintCalendarDayButtonEvent = false
    var hasPaintCalendarMonthButtonEvent = false
    var hasPaintCalendarYearButtonEvent = false
    var hasPaintCalendarHeadDivEvent = false
    func addPaintCalendarDayButtonEvent (callBack:@escaping(FCCalendar, DayButton, FCPaint)->Void){
        hasPaintCalendarDayButtonEvent = true
        onPaintCalendarDayButton = callBack
    }
    func addPaintCalendarMonthButtonEvent (callBack:@escaping(FCCalendar, MonthButton, FCPaint)->Void){
        hasPaintCalendarMonthButtonEvent = true
        onPaintCalendarMonthButton = callBack
    }
    func addPaintCalendarYearButtonEvent (callBack:@escaping(FCCalendar, YearButton, FCPaint)->Void){
        hasPaintCalendarYearButtonEvent = true
        onPaintCalendarYearButton = callBack
    }
    func addPaintCalendarHeadDivEvent (callBack:@escaping(FCCalendar, HeadDiv, FCPaint)->Void){
        hasPaintCalendarHeadDivEvent = true
        onPaintCalendarHeadDiv = callBack
    }
    override init(){
        super.init()
        super.viewType = "calendar"
    }
    func getSelectedDay()->CDay{
        if self.selectedDay.count > 0{
            return self.selectedDay[0]
        }else{
            let noneDay = CDay()
            noneDay.isNotEmpty = false
            return noneDay
        }
    }
    func setSelectedDay(d:CDay){
        self.selectedDay = [CDay]()
        self.selectedDay.append(d)
    }
    func getDayDiv()->DayDiv{
        if self.dayDiv.count > 0{
            return self.dayDiv[0]
        }else{
            let noneDayDiv = DayDiv()
            noneDayDiv.isNotEmpty = false
            return noneDayDiv
        }
    }
    func setDayDiv(d:DayDiv){
        self.dayDiv = [DayDiv]()
        self.dayDiv.append(d)
    }
    func getHeadDiv()->HeadDiv{
        if self.headDiv.count > 0{
            return self.headDiv[0]
        }else{
            let noneHeadDiv = HeadDiv()
            noneHeadDiv.isNotEmpty = false
            return noneHeadDiv
        }
    }
    func setHeadDiv(h:HeadDiv){
        self.headDiv = [HeadDiv]()
        self.headDiv.append(h)
    }
    func getMonthDiv()->MonthDiv{
        if self.monthDiv.count > 0{
            return self.monthDiv[0]
        }else{
            let noneMonthDiv = MonthDiv()
            noneMonthDiv.isNotEmpty = false
            return noneMonthDiv
        }
    }
    func setMonthDiv(m:MonthDiv){
        self.monthDiv = [MonthDiv]()
        self.monthDiv.append(m)
    }
    func getYearDiv()->YearDiv{
        if self.yearDiv.count > 0{
            return self.yearDiv[0]
        }else{
            let noneYearDiv = YearDiv()
            noneYearDiv.isNotEmpty = false
            return noneYearDiv
        }
    }
    func setYearDiv(y:YearDiv){
        self.yearDiv = [YearDiv]()
        self.yearDiv.append(y)
    }
    func getTimeDiv()->TimeDiv{
        if self.timeDiv.count > 0{
            return self.timeDiv[0]
        }else{
            let noneTimeDiv = TimeDiv()
            noneTimeDiv.isNotEmpty = false
            return noneTimeDiv
        }
    }
    func setTimeDiv(td:TimeDiv){
        self.timeDiv = [TimeDiv]()
        timeDiv.append(td)
    }
}

/*
* 日的按钮
*/
class DayButton:NSObject{
    var backColor = "none" //背景颜色
    var borderColor = "rgb(150,150,150)" //文字颜色
    var bounds = FCRect(left:0, top:0, right:0, bottom:0) //显示区域
    var day = [CDay]() //日期
    var font = "Default,16" //字体
    var inThisMonth = false //是否在本月
    var isNotEmpty = false
    var selected = false //是否被选中
    var textColor = "rgb(0,0,0)" //文字颜色
    var textColor2 = "rgb(50,50,50)" //第二个文字颜色
    var visible = true //是否可见
    override init(){
        self.isNotEmpty = true
    }
    func getDay()->CDay{
        if self.day.count > 0{
            return self.day[0]
        }else{
            let noneDay = CDay()
            noneDay.isNotEmpty = false
            return noneDay
        }
    }
    func setDay(d:CDay){
        day = [CDay]()
        day.append(d)
    }
}

/*
* 月的按钮
*/
class MonthButton:NSObject{
    var backColor = "none" //背景颜色
    var borderColor = "rgb(150,150,150)" //文字颜色
    var bounds = FCRect(left:0, top:0, right:0, bottom:0) //显示区域
    var font = "Default,16" //字体
    var isNotEmpty = false
    var month:Int = 0 //月
    var textColor = "rgb(0,0,0)" //文字颜色
    var year:Int = 0 //年
    var visible = true //是否可见
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 年的按钮
*/
class YearButton:NSObject{
    var backColor = "none" //背景颜色
    var borderColor = "rgb(150,150,150)" //文字颜色
    var bounds = FCRect(left:0, top:0, right:0, bottom:0) //显示区域
    var font = "Default,16" //字体
    var isNotEmpty = false
    var textColor = "rgb(0,0,0)" //文字颜色
    var year:Int = 0 //年
    var visible = true //是否可见
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 日期层
*/
class DayDiv:NSObject{
    var aClickRowFrom:Int = 0 //点击时的上月的行
    var aClickRowTo:Int = 0 //点击时的当月的行
    var aDirection:Int = 0 //动画的方向
    var aTick:Int  = 0 //动画当前帧数
    var aTotalTick:Int  = 40 //动画总帧数
    var dayButtons = [DayButton]() //日期的集合
    var dayButtonsAm = [DayButton]() //动画日期的集合
    var isNotEmpty = false
    override init(){
        self.isNotEmpty = true
    }
}

/*
* 菜单
*/
class FCMenu:FCLayoutDiv{
    var autoSize: Bool = true //是否自动适应尺寸
    var comboBox = [FCComboBox]() //所在的下拉菜单
    var items = [FCMenuItem]() //菜单项
    var popup: Bool = true //是否弹出
    override init(){
        super.init()
        super.maximumSize = FCSize(cx:100, cy:300)
        super.viewType = "menu"
        super.size = FCSize(cx:100, cy:100)
        super.showHScrollBar = true
        super.showVScrollBar = true
        super.visible = false
        super.layoutStyle = "toptobottom"
        super.autoWrap = false
        super.allowPreviewsEvent = true
    }
    func getComboBox()->FCComboBox{
        if self.comboBox.count > 0{
            return self.comboBox[0]
        }else{
            let noneComboBox = FCComboBox()
            noneComboBox.isNotEmpty = false
            return noneComboBox
        }
    }
    func setComboBox(c:FCComboBox){
        comboBox = [FCComboBox]()
        comboBox.append(c)
    }
}

/*
* 菜单项
*/
class FCMenuItem:FCView{
    var checked: Bool = false //是否选中
    var dropDownMenu = [FCMenu]() //下拉菜单
    var items = [FCMenuItem]() //菜单项
    var parentMenu = [FCMenu]() //所在菜单
    var parentItem = [FCMenuItem]() //父菜单项
    var value = "" //值
    override init(){
        super.init()
        super.viewType = "menuitem"
        super.hoveredColor = "rgb(150,150,150)"
        super.pushedColor = "rgb(100,100,100)"
        super.size = FCSize(cx:100, cy:25)
    }
    func getDropDownMenu()->FCMenu{
        if self.dropDownMenu.count > 0{
            return self.dropDownMenu[0]
        }else{
            let noneMenu = FCMenu()
            noneMenu.isNotEmpty = false
            return noneMenu
        }
    }
    func setDropDownMenu(m:FCMenu){
        dropDownMenu = [FCMenu]()
        dropDownMenu.append(m)
    }
    func getParentMenu()->FCMenu{
        if(self.parentMenu.count > 0){
            return self.parentMenu[0]
        }else{
            let noneMenu = FCMenu()
            noneMenu.isNotEmpty = false
            return noneMenu
        }
    }
    func setParentMenu(m:FCMenu){
        parentMenu = [FCMenu]()
        parentMenu.append(m)
    }
    func getParentItem()->FCMenuItem{
        if self.parentItem.count > 0{
            return self.parentItem[0]
        }else{
            let noneItem = FCMenuItem()
            noneItem.isNotEmpty = false
            return noneItem
        }
    }
    func setParentItem(m:FCMenuItem){
        parentItem = [FCMenuItem]()
        parentItem.append(m)
    }
}

/*
* 下拉选择
*/
class FCComboBox:FCView{
    var dropDownMenu = [FCMenu]() //下拉菜单
    var selectedIndex:Int = -1 //选中索引
    override init(){
        super.init()
        super.viewType = "combobox"
    }
    func getDropDownMenu()->FCMenu{
        if self.dropDownMenu.count > 0{
            return self.dropDownMenu[0]
        }else{
            let noneMenu = FCMenu()
            noneMenu.isNotEmpty = false
            return noneMenu
        }
    }
    func setDropDownMenu(m:FCMenu){
        dropDownMenu = [FCMenu]()
        dropDownMenu.append(m)
    }
}

/*
 * 保留小数
 * value:数值
 * digit:精度
 */
func toFixed(value:Double, digit:Int)->String{
    if digit == 0{
        return String(format:"%d", Int(value))
    }else{
        let format = "%." + String(digit) + "f"
        return String(format:format, value)
    }
}

/*
* 添加顶层视图
* view 视图
* paint 绘图对象
*/
func addView(view:FCView, paint:FCPaint) {
    view.setPaint(paint:paint)
    paint.views.append(view)
}

/*
* 添加到父视图
* view 视图
* parent 父视图
*/
func addViewToParent(view:FCView, parent:FCView) {
    view.setPaint(paint:parent.getPaint())
    parent.views.append(view)
    view.setParent(parent:parent)
}

/*
* 插入到顶层视图
* view 视图
* paint 绘图对象
* index 索引
*/
func insertView(view:FCView, paint:FCPaint, index:Int) {
    view.setPaint(paint:paint)
    paint.views.insert(view, at:index)
}

/*
* 插入到到父视图
* view 视图
* parent 父视图
* index 索引
*/
func insertViewToParent(view:FCView, parent:FCView, index:Int) {
    view.setPaint(paint:parent.getPaint())
    parent.views.insert(view, at:index)
    view.setParent(parent:parent)
}

/*
 * 清除视图
 * paint 绘图对象
 */
func clearViews(paint:FCPaint){
    paint.views = [FCView]()
}

/*
* 移除顶层视图
* view 视图
* paint 绘图对象
*/
func removeView(view:FCView, paint:FCPaint) {
    if paint.views.count > 0 {
        for i in 0...paint.views.count - 1 {
            if paint.views[i] == view {
                paint.views.remove(at:i)
                break
            }
        }
    }
}

/*
* 从父视图中移除
* view 视图
* parent 父视图
*/
func removeViewFromParent(view:FCView, parent:FCView) {
    if parent.views.count > 0 {
        for i in 0...parent.views.count - 1 {
          if parent.views[i] == view {
              parent.views.remove(at:i)
              break
          }
      }
  }
}

/*
* 获取绝对位置X
* view:视图
*/
func clientX(view:FCView)->Double {
    if view.isNotEmpty {
        let cLeft = view.location.x
        if view.getParent().isNotEmpty {
            let pView = view.getParent()
            if pView.displayOffset && pView.scrollH != 0 {
                return cLeft + clientX(view:pView) - pView.scrollH
            } else {
                return cLeft + clientX(view:pView)
            }
        } else {
            return cLeft
        }
    } else {
        return 0
    }
}

/*
* 获取绝对位置Y
* view:视图
*/
func clientY(view:FCView)->Double {
    if view.isNotEmpty {
      let cTop = view.location.y
      if view.getParent().isNotEmpty {
          let pView = view.getParent()
          if pView.displayOffset && pView.scrollV != 0 {
            return cTop + clientY(view:pView) - pView.scrollV
          } else {
            return cTop + clientY(view:pView)
          }
      } else {
          return cTop
      }
  } else {
      return 0
  }
}

/*
* 是否包含坐标
* view:视图
* mp:坐标
*/
func containsPoint(view:FCView, mp:FCPoint)->Bool{
    if isViewEnabled(view: view){
        let clx = clientX(view:view)
        let cly = clientY(view:view)
        let size = view.size
        let cp = FCPoint(x:mp.x - clx, y:mp.y - cly)
        if cp.x >= 0 && cp.x <= size.cx &&
            cp.y >= 0 && cp.y <= size.cy {
            return true
        } else {
            return false
        }
    }else{
        return false
    }
}

/*
* 查找有预处理事件的父视图
* view:视图
*/
func findPreviewsEventParent(view:FCView)->FCView {
    if !view.allowPreviewsEvent && view.getParent().isNotEmpty {
        if view.getParent().allowPreviewsEvent {
            return view.getParent()
        } else {
            return findPreviewsEventParent(view:view.getParent())
        }
    } else {
        let noneView = FCView()
        noneView.isNotEmpty = false
        return noneView
    }
}

/*
* 根据名称查找视图
* name:名称
* views:视图集合
*/
func findViewByName(name:String, views:[FCView])->FCView {
    let size = views.count
    if size > 0{
        for i in 0...size - 1 {
            let view = views[i]
            if view.viewName == name {
                return view
            } else {
                if view.views.count > 0 {
                    let subView = findViewByName(name:name, views:view.views)
                    if subView.isNotEmpty {
                        return subView
                    }
                }
            }
        }
    }
    let noneView = FCView()
    noneView.isNotEmpty = false
    return noneView
}

/*
* 根据坐标查找视图
* mp:坐标
* views:视图集合
*/
func findView(mp:FCPoint, views:[FCView])->FCView {
    let size = views.count
    if size > 0{
        for i in 0...size - 1{
            let view = views[size - i - 1]
            if view.visible && view.topMost {
                var hasPoint = false;
                if(view.getPaint().hasContainsPointEvent){
                    hasPoint = view.getPaint().onContainsPoint(view, mp)
                }else{
                    hasPoint = containsPoint(view:view, mp:mp)
                }
                if hasPoint {
                    if view.vScrollIsVisible {
                        let clx = clientX(view:view)
                        if mp.x >= clx + view.size.cx - view.scrollSize {
                            return view
                        }
                    }
                    if view.hScrollIsVisible {
                        let cly = clientY(view:view)
                        if mp.y >= cly + view.size.cy - view.scrollSize {
                            return view
                        }
                    }
                    if view.views.count > 0 {
                        let subView = findView(mp:mp, views:view.views)
                        if subView.isNotEmpty {
                            return subView
                        }
                    }
                    return view
                }
            }
        }
        for i in 0...size - 1{
            let view = views[size - i - 1]
            if view.visible && !view.topMost {
                var hasPoint = false;
                if(view.getPaint().hasContainsPointEvent){
                    hasPoint = view.getPaint().onContainsPoint(view, mp)
                }else{
                    hasPoint = containsPoint(view:view, mp:mp)
                }
                if hasPoint {
                    if view.vScrollIsVisible {
                        let clx = clientX(view:view)
                        if mp.x >= clx + view.size.cx - view.scrollSize {
                            return view
                        }
                    }
                    if view.hScrollIsVisible {
                        let cly = clientY(view:view)
                        if mp.y >= cly + view.size.cy - view.scrollSize {
                            return view
                        }
                    }
                    if view.views.count > 0 {
                        let subView = findView(mp:mp, views:view.views)
                        if subView.isNotEmpty {
                            return subView
                        }
                    }
                    return view
                }
            }
        }
    }
    let noneView = FCView()
    noneView.isNotEmpty = false
    return noneView
}

/*
* 是否重绘时可见
* view:视图
*/
func isPaintVisible(view:FCView)->Bool {
    if view.visible {
        if view.getParent().isNotEmpty {
            let pView = view.getParent()
            if pView.visible {
                return isPaintVisible(view:pView)
            } else {
                return false
            }
        } else {
            return true
        }
    } else {
        return false
    }
}

/*
* 是否可用
* view:视图
*/
func isViewEnabled(view:FCView)->Bool {
    if view.enabled {
        if view.getParent().isNotEmpty {
            let pView = view.getParent()
            if pView.enabled {
                return isViewEnabled(view:pView)
            } else {
                return false
            }
        } else {
            return true
        }
    } else {
        return false
    }
}

/*
* 获取区域的交集
*/
func getIntersectRect(lpDestRect:inout FCRect, lpSrc1Rect:FCRect, lpSrc2Rect:FCRect)->Int{
    lpDestRect.left = max(lpSrc1Rect.left, lpSrc2Rect.left)
    lpDestRect.right = min(lpSrc1Rect.right, lpSrc2Rect.right)
    lpDestRect.top = max(lpSrc1Rect.top, lpSrc2Rect.top)
    lpDestRect.bottom = min(lpSrc1Rect.bottom, lpSrc2Rect.bottom)
    if lpDestRect.right > lpDestRect.left && lpDestRect.bottom > lpDestRect.top {
        return 1
    }
    else {
        lpDestRect.left = 0
        lpDestRect.right = 0
        lpDestRect.top = 0
        lpDestRect.bottom = 0
        return 0
    }
}

/*
* 重绘视图
* views:视图集合
* paint:绘图对象
* rect:区域
*/
func renderViews(views:[FCView], paint:FCPaint, rect:FCRect) {
    var viewsSize = views.count
    if(viewsSize > 0){
         for i in 0...viewsSize - 1 {
            let view = views[i]
            if !rect.isNotEmpty{
                let noneRect = FCRect(left:0, top:0, right:0, bottom:0)
                noneRect.isNotEmpty = false
                if view.views.count > 0 {
                    let subViewsSize = view.views.count
                    if subViewsSize > 0 {
                        renderViews(views:view.views, paint:paint, rect:noneRect)
                    }
                }
                view.clipRect = noneRect
                continue
            }
            if !view.topMost && isPaintVisible(view:view) {
                let clx = clientX(view:view)
                let cly = clientY(view:view)
                let drawRect = FCRect(left:0, top:0, right:view.size.cx, bottom:view.size.cy)
                let clipRect = FCRect(left:clx, top:cly, right:clx + view.size.cx, bottom:cly + view.size.cy)
                var destRect = FCRect(left:0, top:0, right:0, bottom:0)
                if getIntersectRect(lpDestRect:&destRect, lpSrc1Rect:rect, lpSrc2Rect:clipRect) > 0
                {
                    paint.save()
                    paint.setOffset(x: 0, y: 0)
                    paint.setClip(left:destRect.left, top:destRect.top, right:destRect.right, bottom:destRect.bottom)
                    view.clipRect = destRect
                    paint.setOffset(x:clx, y:cly)
                    if paint.hasPaintEvent{
                        paint.onPaint(view, paint, drawRect)
                    }else{
                        onPaintDefault(view: view, paint: paint, clipRect: drawRect)
                    }
                    if view.views.count > 0 {
                        let subViewsSize = view.views.count
                        if subViewsSize > 0 {
                            renderViews(views:view.views, paint:paint, rect:destRect)
                        }
                    }
                    paint.setOffset(x:clx, y:cly)
                    if paint.hasPaintBorderEvent{
                        paint.onPaintBorder(view, paint, drawRect)
                    }else{
                        onPaintBorderDefault(view: view, paint: paint, clipRect: drawRect)
                    }
                    paint.restore()
                } else {
                    let noneRect = FCRect(left:0, top:0, right:0, bottom:0)
                    if view.views.count > 0 {
                        let subViewsSize = view.views.count
                        if subViewsSize > 0 {
                            renderViews(views:view.views, paint:paint, rect:noneRect)
                        }
                    }
                    view.clipRect = noneRect
                }
            }
        }
        viewsSize = views.count
        for i in 0...viewsSize - 1 {
            let view = views[i]
            if !rect.isNotEmpty {
                let noneRect = FCRect(left:0, top:0, right:0, bottom:0)
                noneRect.isNotEmpty = false
                if view.views.count > 0{
                    let subViewsSize = view.views.count
                    if subViewsSize > 0 {
                        renderViews(views:view.views, paint:paint, rect:noneRect)
                    }
                }
                view.clipRect = noneRect
                continue
            }
            if view.topMost && isPaintVisible(view:view) {
                let clx = clientX(view:view)
                let cly = clientY(view:view)
                let drawRect = FCRect(left:0, top:0, right:view.size.cx, bottom:view.size.cy)
                let clipRect = FCRect(left:clx, top:cly, right:clx + view.size.cx, bottom:cly + view.size.cy)
                var destRect = FCRect(left:0, top:0, right:0, bottom:0)
                if getIntersectRect(lpDestRect:&destRect, lpSrc1Rect:rect, lpSrc2Rect:clipRect) > 0
                {
                    paint.save()
                    paint.setOffset(x: 0, y: 0)
                    paint.setClip(left:destRect.left, top:destRect.top, right:destRect.right, bottom:destRect.bottom)
                    view.clipRect = destRect
                    paint.setOffset(x:clx, y:cly)
                    if paint.hasPaintEvent{
                        paint.onPaint(view, paint, drawRect)
                    }else{
                        onPaintDefault(view: view, paint: paint, clipRect: drawRect)
                    }
                    if view.views.count > 0 {
                        let subViewsSize = view.views.count
                        if subViewsSize > 0 {
                            renderViews(views:view.views, paint:paint, rect:destRect)
                        }
                    }
                    paint.setOffset(x:clx, y:cly)
                    if paint.hasPaintBorderEvent{
                        paint.onPaintBorder(view, paint, drawRect)
                    }else{
                        onPaintBorderDefault(view: view, paint: paint, clipRect: drawRect)
                    }
                    paint.restore()
                } else {
                    let noneRect = FCRect(left:0, top:0, right:0, bottom:0)
                    if view.views.count > 0 {
                        let subViewsSize = view.views.count
                        if subViewsSize > 0 {
                            renderViews(views:view.views, paint:paint, rect:noneRect)
                        }
                    }
                    view.clipRect = noneRect
                }
            }
        }
    }
}

/*
* 全局刷新方法
* paint:绘图对象
*/
func invalidate(paint:FCPaint) {
    if paint.hasInvalidateEvent{
        paint.onInvalidate(paint)
    }else{
        paint.getUIView().setNeedsDisplay(paint.getUIView().frame)
    }
}

/*
* 刷新视图方法
* view:视图
*/
func invalidateView(view:FCView) {
    let paint = view.getPaint()
    if paint.hasInvalidateViewEvent{
        paint.onInvalidateView(view)
    }else{
        let clx = clientX(view: view)
        let cly = clientY(view: view)
        let rect = CGRect(x: clx * paint.scaleFactorX, y: paint.getUIView().frame.size.height - cly * paint.scaleFactorY - view.size.cy * paint.scaleFactorY, width: view.size.cx * paint.scaleFactorX, height: view.size.cy * paint.scaleFactorY)
        paint.getUIView().setNeedsDisplay(rect)
    }
}

/*
* 更新悬浮状态
* views:视图集合
*/
func updateViewDefault(views:[FCView]) {
    if views.count > 0{
        for i in 0...views.count - 1 {
            let view = views[i]
            let pView = view.getParent()
            if var newStr = view.exAttributes["leftstr"]{
                var pWidth = view.getPaint().size.cx / view.getPaint().scaleFactorX
                if pView.isNotEmpty{
                    pWidth = pView.size.cx
                }
                newStr = newStr.replacingOccurrences(of: "%", with: "")
                view.location.x = Double(StringToFloat(str:newStr)) * pWidth / 100
            }
            if var newStr = view.exAttributes["topstr"]{
                var pHeight = view.getPaint().size.cy / view.getPaint().scaleFactorY
                if pView.isNotEmpty{
                    pHeight = pView.size.cy
                }
                newStr = newStr.replacingOccurrences(of: "%", with: "")
                view.location.y = Double(StringToFloat(str:newStr)) * pHeight / 100
            }
            if var newStr = view.exAttributes["widthstr"]{
                var pWidth = view.getPaint().size.cx / view.getPaint().scaleFactorX
                if pView.isNotEmpty{
                    pWidth = pView.size.cx
                }
                newStr = newStr.replacingOccurrences(of: "%", with: "")
                view.size.cx = Double(StringToFloat(str:newStr)) * pWidth / 100
            }
            if var newStr = view.exAttributes["heightstr"]{
                var pHeight = view.getPaint().size.cy / view.getPaint().scaleFactorY
                if pView.isNotEmpty{
                    pHeight = pView.size.cy
                }
                newStr = newStr.replacingOccurrences(of: "%", with: "")
                view.size.cy = Double(StringToFloat(str:newStr)) * pHeight / 100
            }
            if pView.isNotEmpty && pView.viewType != "split" {
                let margin = view.margin;
                let padding = view.padding;
                if view.dock == "fill" {
                    view.location = FCPoint(x:margin.left + padding.left, y:margin.top + padding.top)
                    var vcx = pView.size.cx - margin.left - padding.left - margin.right - padding.right
                    if vcx < 0{
                        vcx = 0
                    }
                    var vcy = pView.size.cy - margin.top - padding.top - margin.bottom - padding.bottom
                    if vcy < 0{
                        vcy = 0
                    }
                    view.size = FCSize(cx:vcx, cy:vcy)
                } else if view.dock == "left" {
                    view.location = FCPoint(x:margin.left + padding.left, y:margin.top + padding.top)
                    var vcy = pView.size.cy - margin.top - padding.top - margin.bottom - padding.bottom
                    if vcy < 0{
                        vcy = 0
                    }
                    view.size = FCSize(cx:view.size.cx, cy:vcy)
                } else if view.dock == "top" {
                    view.location = FCPoint(x:margin.left + padding.left, y:margin.top + padding.top)
                    var vcx = pView.size.cx - margin.left - padding.left - margin.right - padding.right
                    if vcx < 0{
                        vcx = 0
                    }
                    view.size = FCSize(cx:vcx, cy:view.size.cy)
                } else if view.dock == "right" {
                    view.location = FCPoint(x:pView
                        .size.cx - view.size.cx - padding.right - margin.right, y:margin.top + padding.top)
                    var vcy = pView.size.cy - margin.top - padding.top - margin.bottom - padding.bottom
                    if vcy < 0{
                        vcy = 0
                    }
                    view.size = FCSize(cx:view.size.cx, cy:vcy)
                } else if view.dock == "bottom" {
                    view.location = FCPoint(x:margin.left + padding.left, y:pView.size.cy - view.size.cy - margin.bottom - padding.bottom)
                    var vcx = pView.size.cx - margin.left - padding.left - margin.right - padding.right
                    if vcx < 0{
                        vcx = 0
                    }
                    view.size = FCSize(cx:vcx, cy:view.size.cy)
                }
                if view.align == "center" {
                    view.location = FCPoint(x:(pView.size.cx - view.size.cx) / 2, y:view.location.y)
                }else if view.align == "right"{
                    view.location = FCPoint(x:pView.size.cx - view.size.cx - padding.right - margin.right, y:view.location.y)
                }
                if view.verticalAlign == "middle" {
                    view.location = FCPoint(x:view.location.x, y:(pView.size.cy - view.size.cy) / 2)
                }else if view.verticalAlign == "bottom"{
                    view.location = FCPoint(x:view.location.x, y:pView.size.cy - view.size.cy - padding.bottom - margin.bottom)
                }
            }else{
                if !pView.isNotEmpty && view.dock == "fill"{
                    view.size = FCSize(cx:view.getPaint().size.cx / view.getPaint().scaleFactorX, cy:view.getPaint().size.cy / view.getPaint().scaleFactorY)
                }
            }
            if view.viewType == "split" {
                resetSplitLayoutDiv(split: view as! FCSplitLayoutDiv)
            } else if view.viewType == "tabview" {
                updateTabLayout(tabView:view as! FCTabView)
            } else if view.viewType == "layout" {
                resetLayoutDiv(layout: view as! FCLayoutDiv)
            } else if view.viewType == "calendar" {
                updateCalendar(calendar: view as! FCCalendar)
            } else if view.viewType == "chart"{
                let chart = view as! FCChart
                resetChartVisibleRecord(chart:chart)
                checkChartLastVisibleIndex(chart:chart)
                if chart.hasCalculateChartMaxMinEvent{
                    chart.onCalculateChartMaxMin(chart)
                }
                else if chart.getPaint().hasCalculateChartMaxMinEvent{
                    chart.getPaint().onCalculateChartMaxMin(chart)
                }else{
                    calculateChartMaxMin(chart:chart)
                }
            }
            if view.views.count > 0 {
                updateViewDefault(views:view.views)
            }
        }
    }
}

/*
* 视图尺寸改变
*/
func windowResize(rect:FCRect, resizePoint:Int, nowPoint:FCPoint, startTouchPoint:FCPoint){
    if resizePoint == 0{
        rect.left = rect.left + nowPoint.x - startTouchPoint.x
        rect.top = rect.top + nowPoint.y - startTouchPoint.y
    }
    else if resizePoint == 1{
        rect.left = rect.left + nowPoint.x - startTouchPoint.x
        rect.bottom = rect.bottom + nowPoint.y - startTouchPoint.y
    }
    else if resizePoint == 2{
        rect.right = rect.right + nowPoint.x - startTouchPoint.x
        rect.top = rect.top + nowPoint.y - startTouchPoint.y
    }
    else if resizePoint == 3{
        rect.right = rect.right + nowPoint.x - startTouchPoint.x
        rect.bottom = rect.bottom + nowPoint.y - startTouchPoint.y
    }
    else if resizePoint == 4{
        rect.left = rect.left + nowPoint.x - startTouchPoint.x
    }
    else if resizePoint == 5{
        rect.top = rect.top + nowPoint.y - startTouchPoint.y
    }
    else if resizePoint == 6{
        rect.right = rect.right + nowPoint.x - startTouchPoint.x
    }
    else if resizePoint == 7{
        rect.bottom = rect.bottom + nowPoint.y - startTouchPoint.y
    }
}

/*
* 获取调整尺寸的点
*/
func getResizeState(view:FCView, mp:FCPoint)->Int{
    let bWidth = 5.0;
    let width = view.size.cx, height = view.size.cy;
    if (mp.x >= 0 && mp.x <= bWidth * 2.0 && mp.y >= 0 && mp.y <= bWidth * 2.0){
        return 0
    }else if (mp.x >= 0 && mp.x <= bWidth * 2.0 && mp.y >= height - bWidth * 2.0 && mp.y <= height){
        return 1
    }else if (mp.x >= width - bWidth * 2.0 && mp.x <= width && mp.y >= 0 && mp.y <= bWidth * 2){
        return 2
    }else if (mp.x >= width - bWidth * 2.0 && mp.x <= width && mp.y >= height - bWidth * 2.0 && mp.y <= height){
        return 3
    }else if (mp.x >= 0 && mp.x <= bWidth && mp.y >= 0 && mp.y <= height){
        return 4
    }else if (mp.x >= 0 && mp.x <= width && mp.y >= 0 && mp.y <= bWidth){
        return 5
    }else if (mp.x >= width - bWidth && mp.x <= width && mp.y >= 0 && mp.y <= height){
        return 6
    }else if (mp.x >= 0 && mp.x <= width && mp.y >= height - bWidth && mp.y <= height){
        return 7
    }else{
        return -1
    }
}

/*
 * 跨线程调用
 * view:视图
 * args:数据
 */
func beginInvoke(view:FCView, args:NSObject){
    DispatchQueue.main.async {
        let paint = view.getPaint()
        if view.hasInvokeEvent{
            view.onInvoke(view, args)
        }else if paint.hasInvokeEvent{
            paint.onInvoke(view, args)
        }
    }
}

/*
* 重绘复选按钮
* checkBox:视图
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawCheckBox(checkBox:FCCheckBox, paint:FCPaint, clipRect:FCRect){
    let width = checkBox.size.cx
    let height = checkBox.size.cy
    if checkBox.textColor != "none" {
        let eRight = checkBox.buttonSize.cx + 10
        var eRect = FCRect(left:1, top:(height - checkBox.buttonSize.cy) / 2, right:checkBox.buttonSize.cx + 1, bottom:(height + checkBox.buttonSize.cy) / 2)
        if checkBox.text.count == 0{
            eRect = FCRect(left:(width - checkBox.buttonSize.cx) / 2, top:(height - checkBox.buttonSize.cy) / 2, right:(width + checkBox.buttonSize.cx) / 2, bottom:(height + checkBox.buttonSize.cy) / 2)
        }
        paint.drawRect(color:checkBox.textColor, width:1, style:[], left:eRect.left, top:eRect.top, right:eRect.right, bottom:eRect.bottom)
        if checkBox.checked {
            eRect.left += 2
            eRect.top += 2
            eRect.right -= 2
            eRect.bottom -= 2
            paint.beginPath()
            paint.addLine(x1:eRect.left, y1:eRect.top + 8, x2:eRect.left + 6, y2:eRect.bottom)
            paint.addLine(x1:eRect.left + 6, y1:eRect.bottom, x2:eRect.right - 1, y2:eRect.top)
            paint.drawPath(color:checkBox.textColor, width:1, style:[])
            paint.closePath()
        }
        if checkBox.text.count > 0{
            let tSize = paint.textSize(text:checkBox.text, font:checkBox.font)
            paint.drawText(text:checkBox.text, color:checkBox.textColor, font:checkBox.font, x:eRight, y:(height - tSize.cy) / 2)
        }
    }
}

/*
* 重绘单选按钮
* radioButton:视图
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawRadioButton(radioButton:FCRadioButton, paint:FCPaint, clipRect:FCRect) {
    let height = radioButton.size.cy
    if radioButton.textColor != "none" {
        let eRight = radioButton.buttonSize.cx + 10
        let eRect = FCRect(left:1, top:(height - radioButton.buttonSize.cy) / 2, right:radioButton.buttonSize.cx + 1, bottom:(height + radioButton.buttonSize.cy) / 2)
        paint.drawEllipse(color:radioButton.textColor, width:1, style:[], left:eRect.left, top:eRect.top, right:eRect.right, bottom:eRect.bottom)
        if radioButton.checked {
            eRect.left += 2
            eRect.top += 2
            eRect.right -= 2
            eRect.bottom -= 2
            paint.fillEllipse(color:radioButton.textColor, left:eRect.left, top:eRect.top, right:eRect.right, bottom:eRect.bottom)
        }
        let tSize = paint.textSize(text:radioButton.text, font:radioButton.font)
        paint.drawText(text:radioButton.text, color:radioButton.textColor, font:radioButton.font, x:eRight, y:(height - tSize.cy) / 2)
    }
}

/*
* 重绘按钮
* button:视图
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawButton(button:FCView, paint:FCPaint, clipRect:FCRect) {
    if button == button.getPaint().getTouchDownView() {
        if button.pushedColor != "none" {
            paint.fillRoundRect(color:button.pushedColor, left:0, top:0, right:button.size.cx, bottom:button.size.cy, cornerRadius: button.cornerRadius)
        } else {
            if button.backColor != "none" {
                paint.fillRoundRect(color:button.backColor, left:0, top:0, right:button.size.cx, bottom:button.size.cy, cornerRadius: button.cornerRadius)
            }
        }
    } else if button == button.getPaint().getTouchMoveView() {
        if button.hoveredColor != "none" {
            paint.fillRoundRect(color:button.hoveredColor, left:0, top:0, right:button.size.cx, bottom:button.size.cy, cornerRadius: button.cornerRadius)
        } else {
            if button.backColor != "none" {
                paint.fillRoundRect(color:button.backColor, left:0, top:0, right:button.size.cx, bottom:button.size.cy, cornerRadius: button.cornerRadius)
            }
        }
    }
    else if button.backColor != "none" {
        paint.fillRoundRect(color:button.backColor, left:0, top:0, right:button.size.cx, bottom:button.size.cy, cornerRadius: button.cornerRadius)
    }
    if button.textColor != "none" && button.text.count > 0 {
        let tSize = paint.textSize(text:button.text, font:button.font)
        paint.drawText(text:button.text, color:button.textColor, font:button.font, x:(button.size.cx - tSize.cx) / 2, y:(button.size.cy - tSize.cy) / 2)
    }
    if button.borderColor != "none" {
        paint.drawRoundRect(color:button.borderColor, width:button.borderWidth, style:[], left:0, top:0, right:button.size.cx, bottom:button.size.cy, cornerRadius: button.cornerRadius)
    }
}

/*
* 点击复选按钮
* checkBox:视图
* mp:坐标
*/
func clickCheckBox(checkBox:FCCheckBox, mp:FCPoint) {
    checkBox.checked = !checkBox.checked
}

/*
* 点击单选按钮
* radioButton:视图
* mp:坐标
*/
func clickRadioButton(radioButton:FCRadioButton, mp:FCPoint) {
    if radioButton.getParent().isNotEmpty && radioButton.getParent().views.count > 0 {
        for i in 0...radioButton.getParent().views.count - 1{
            let rView = radioButton.getParent().views[i]
            if rView is FCRadioButton{
                let rButton = rView as! FCRadioButton
                if rView != radioButton &&
                        rButton.groupName == radioButton.groupName{
                    rButton.checked = false
                }
            }
        }
    }
    radioButton.checked = true
}

/*
* 获取月的日数
* year:年
* month:月
*/
func getDaysInMonth(year:Int, month:Int)->Int {
    switch month {
        case 1:
            return 31
        case 3:
            return 31
        case 5:
            return 31
        case 7:
            return 31
        case 8:
            return 31
        case 10:
            return 31
        case 12:
            return 31
        case 4:
            return 30
        case 6:
            return 30
        case 9:
            return 30
        case 11:
            return 30
        case 2:
            if (year % 4 == 0 && year % 100 != 0) || year % 400 == 0{
                    return 29
          }
                else{
                    return 28
          }
    default:
        return 0
    }
}

/*
* 根据字符获取月份
* month:月
*/
func getMonthStr(month:Int)->String{
    switch month {
        case 1:
            return "一月"
        case 2:
            return "二月"
        case 3:
            return "三月"
        case 4:
            return "四月"
        case 5:
            return "五月"
        case 6:
            return "六月"
        case 7:
            return "七月"
        case 8:
            return "八月"
        case 9:
            return "九月"
        case 10:
            return "十月"
        case 11:
            return "十一月"
        case 12:
            return "十二月"
        default:
            return ""
    }
}

/*
* 获取年
* years:年的集合
* year:年
*/
func getYear(years:inout Dictionary<Int,CYear>, year:Int)->CYear
{
    var cy = CYear()
    if years[year] == nil {
        cy = CYear()
        cy.year = year
        years[year] = cy
        for i in 1...12{
            let cMonth = CMonth()
            cMonth.year = year
            cMonth.month = i
            cy.months[i] = cMonth
            let daysInMonth = getDaysInMonth(year:year, month:i)
            for j in 1...daysInMonth {
                let cDay = CDay()
                cDay.year = year
                cDay.month = i
                cDay.day = j
                cMonth.days[j] = cDay
            }
        }
    }
    else {
        if let cYear = years[year]{
            cy = cYear
        }
    }
    return cy
}

/*
* 显示隐藏日期层
* dayDiv:日期层
* visible:是否可见
*/
func showOrHideDayDiv(dayDiv:DayDiv, visible:Bool) {
    let dayButtonSize = dayDiv.dayButtons.count
    for i in 0...dayButtonSize - 1{
        let dayButton = dayDiv.dayButtons[i]
        dayButton.visible = visible
    }
}

/*
* 显示隐藏月层
* monthDiv:月层
* visible:是否可见
*/
func showOrHideMonthDiv(monthDiv:MonthDiv, visible:Bool) {
    let monthButtonSize = monthDiv.monthButtons.count
    for i in 0...monthButtonSize - 1{
        let monthButton = monthDiv.monthButtons[i]
        monthButton.visible = visible
    }
}

/*
* 显示隐藏年层
* yearButtons:年层
* visible:是否可见
*/
func showOrHideYearDiv(yearDiv:YearDiv, visible:Bool) {
    let yearButtonSize = yearDiv.yearButtons.count
    for i in 0...yearButtonSize - 1{
        let yearButton = yearDiv.yearButtons[i]
        yearButton.visible = visible
    }
}

/*
* 初始化日历
* calendar:日历
*/
func initCalendar(calendar:FCCalendar) {
    calendar.setDayDiv(d:DayDiv())
    calendar.setMonthDiv(m:MonthDiv())
    calendar.setYearDiv(y:YearDiv())
    calendar.setHeadDiv(h:HeadDiv())
    calendar.setTimeDiv(td:TimeDiv())
    for _ in 0...41 {
        let dayButton = DayButton()
        calendar.getDayDiv().dayButtons.append(dayButton)
        let dayFCButtonm = DayButton()
        dayFCButtonm.visible = false
        calendar.getDayDiv().dayButtonsAm.append(dayFCButtonm)
    }
    for i in 0...41 {
        let monthButton = MonthButton()
        monthButton.month = (i + 1)
        calendar.getMonthDiv().monthButtons.append(monthButton)
        let monthButtonAm = MonthButton()
        monthButtonAm.visible = false
        monthButtonAm.month = (i + 1)
        calendar.getMonthDiv().monthButtonsAm.append(monthButtonAm)
    }

    for _ in 0...41 {
        let yearButton = YearButton()
        calendar.getYearDiv().yearButtons.append(yearButton)
        let yearButtonAm = YearButton()
        yearButtonAm.visible = false
        calendar.getYearDiv().yearButtonsAm.append(yearButtonAm)
    }
}

/*
* 获取星期
* y:年
* m:月
* d:日
*/
func dayOfWeek(y:Int, m:Int, d:Int)->Int {
    var mm = m, yy = y
    if mm == 1 || mm == 2{
       mm += 12
       yy -= 1
   }
   return Int(((d + 2 * mm + 3 * (mm + 1) / 5 + yy + yy / 4 - yy / 100 + yy / 400) + 1) % 7)
}

/*
* 获取当月
* calendar:日历
*/
func getMonth(calendar:FCCalendar)->CMonth {
    let cYear = getYear(years:&calendar.years, year:calendar.getSelectedDay().year)
    if let cMonth = cYear.months[calendar.getSelectedDay().month]{
        return cMonth
    }else{
        let noneMonth = CMonth()
        noneMonth.isNotEmpty = false
        return noneMonth
    }
}

/*
* 获取下个月
* calendar:日历
* year:年
* month:月
*/
func getNextMonth(calendar:FCCalendar, year:Int, month:Int)->CMonth {
    var nextMonth = month + 1
    var nextYear = year
    if nextMonth == 13 {
      nextMonth = 1
      nextYear += 1
    }
    if let cMonth = getYear(years:&calendar.years, year:nextYear).months[nextMonth]{
        return cMonth
    }else{
        let noneMonth = CMonth()
        noneMonth.isNotEmpty = false
        return noneMonth
    }
}

/*
* 获取上个月
* calendar:日历
* year:年
* month:月
*/
func getLastMonth(calendar:FCCalendar, year:Int, month:Int)->CMonth {
    var lastMonth = month - 1
    var lastYear = year
    if lastMonth == 0 {
        lastMonth = 12
        lastYear -= 1
    }
    if let cMonth = getYear(years:&calendar.years, year:lastYear).months[lastMonth]{
        return cMonth
    }else{
        let noneMonth = CMonth()
        noneMonth.isNotEmpty = false
        return noneMonth
    }
}

/*
* 重置日期层布局
* calendar:日历
* dayDiv:日期层
* state:状态
*/
func resetDayDiv(calendar:FCCalendar, dayDiv:DayDiv, state:Int) {
    var thisMonth = getMonth(calendar:calendar)
    var lastMonth = getLastMonth(calendar:calendar, year:thisMonth.year, month:thisMonth.month)
    var nextMonth = getNextMonth(calendar:calendar, year:thisMonth.year, month:thisMonth.month)
    var left = 0.0
    let headHeight = calendar.getHeadDiv().bounds.bottom
    var top = headHeight
    let width = calendar.size.cx
    var height = calendar.size.cy
    height -= calendar.getTimeDiv().bounds.bottom - calendar.getTimeDiv().bounds.top
    var dayButtonHeight = height - headHeight
    if dayButtonHeight < 1 {
        dayButtonHeight = 1
    }
    var toY = 0.0
    if dayDiv.aDirection == 1 {
        toY = dayButtonHeight * Double(dayDiv.aTick) / Double(dayDiv.aTotalTick)
        if state == 1 {
            thisMonth = nextMonth
            let month = thisMonth.month
            lastMonth = getLastMonth(calendar:calendar, year:thisMonth.year, month:month)
            nextMonth = getNextMonth(calendar:calendar, year:thisMonth.year, month:month)
        }
    }
    else if dayDiv.aDirection == 2 {
        toY = -dayButtonHeight * Double(dayDiv.aTick) / Double(dayDiv.aTotalTick)
        if state == 1 {
            thisMonth = lastMonth
            let month = thisMonth.month
            lastMonth = getLastMonth(calendar:calendar, year:thisMonth.year, month:month)
            nextMonth = getNextMonth(calendar:calendar, year:thisMonth.year, month:month)
        }
    }
    var buttonSize = 0
    if state == 0 {
        buttonSize = dayDiv.dayButtons.count
    }
    else if state == 1 {
        buttonSize = dayDiv.dayButtonsAm.count
    }
    var dheight = dayButtonHeight / 6
    let days = thisMonth.days
    if let firstDay = days[1]{
        let startDayOfWeek = dayOfWeek(y:firstDay.year, m:firstDay.month, d:firstDay.day)
        for i in 0...buttonSize - 1{
            var dayButton = DayButton()
            if state == 0 {
                dayButton = dayDiv.dayButtons[i]
                buttonSize = dayDiv.dayButtons.count
            }
            else if state == 1 {
                dayButton = dayDiv.dayButtonsAm[i]
                buttonSize = dayDiv.dayButtonsAm.count
            }
            if i == 35 {
                dheight = height - top
            }
            var vOffset = 0.0
            if state == 1 {
                if dayDiv.aTick > 0 {
                    dayButton.visible = true
                    if dayDiv.aDirection == 1 {
                        vOffset = toY - dayButtonHeight
                    }
                    else if dayDiv.aDirection == 2{
                        vOffset = toY + dayButtonHeight

                    }
                }
                else {
                    dayButton.visible = false
                    continue
                }
            }
            else {
                vOffset = toY
            }
            if (i + 1) % 7 == 0 {
                let dp = FCPoint(x:left, y:top + vOffset)
                let ds = FCSize(cx:width - left, cy:dheight)
                let bounds = FCRect(left:dp.x, top:dp.y, right:dp.x + ds.cx, bottom:dp.y + ds.cy)
                dayButton.bounds = bounds
                left = 0
                if i != 0 && i != buttonSize - 1 {
                    top += dheight
                }
            }
            else {
                let dp = FCPoint(x:left, y:top + vOffset)
                let ds = FCSize(cx:width / 7, cy:dheight)
                //let ds = FCSize(cx:width / 7 + Double(((i + 1) % 7) % 2), cy:dheight)
                let bounds = FCRect(left:dp.x, top:dp.y, right:dp.x + ds.cx, bottom:dp.y + ds.cy)
                dayButton.bounds = bounds
                left += ds.cx
            }
            var cDay = CDay()
            dayButton.inThisMonth = false
            if i >= startDayOfWeek && i <= startDayOfWeek + days.count - 1 {
                if let sDay = days[i - startDayOfWeek + 1]{
                    cDay = sDay
                }
                dayButton.inThisMonth = true
            }
            else if i < startDayOfWeek {
                if let sDay = lastMonth.days[lastMonth.days.count - startDayOfWeek + i + 1]{
                    cDay = sDay
                }
            }
            else if i > startDayOfWeek + days.count - 1 {
                if let sDay = nextMonth.days[i - startDayOfWeek - days.count + 1]{
                    cDay = sDay
                }
            }
            dayButton.setDay(d:cDay)
            if state == 0 && dayButton.getDay().isNotEmpty && dayButton.getDay() == calendar.getSelectedDay() {
                dayButton.selected = true
            }
            else {
                dayButton.selected = false
            }
        }
    }
}

/*
* 重置月层布局
* calendar:日历
* monthDiv:月层
* state:状态
*/
func resetMonthDiv(calendar:FCCalendar, monthDiv:MonthDiv, state:Int) {
    var thisYear = monthDiv.year
    var lastYear = monthDiv.year - 1
    var nextYear = monthDiv.year + 1
    var left = 0.0
    let headHeight = calendar.getHeadDiv().bounds.bottom
    var top = headHeight
    let width = calendar.size.cx
    var height = calendar.size.cy
    height -= calendar.getTimeDiv().bounds.bottom - calendar.getTimeDiv().bounds.top
    var monthButtonHeight = height - top
    if monthButtonHeight < 1 {
        monthButtonHeight = 1
    }
    var toY = 0.0
    var monthButtons = [MonthButton]()
    if monthDiv.aDirection == 1 {
        toY = monthButtonHeight * Double(monthDiv.aTick) / Double(monthDiv.aTotalTick)
        if state == 1 {
            thisYear = nextYear
            lastYear = thisYear - 1
            nextYear = thisYear + 1
        }
    }
    else if monthDiv.aDirection == 2 {
        toY = -monthButtonHeight * Double(monthDiv.aTick) / Double(monthDiv.aTotalTick)
        if state == 1 {
            thisYear = lastYear
            lastYear = thisYear - 1
            nextYear = thisYear + 1
        }
    }
    if state == 0 {
        monthButtons = monthDiv.monthButtons
    }
    else if state == 1 {
        monthButtons = monthDiv.monthButtonsAm
    }
    var dheight = monthButtonHeight / 3
    let buttonSize = monthButtons.count
    for i in 0...buttonSize - 1{
        if i == 8 {
            dheight = height - top
        }
        let monthButton = monthButtons[i]
        monthButton.year = thisYear
        var vOffSet = 0.0
        if state == 1 {
            if monthDiv.aTick > 0 {
                monthButton.visible = true
                if monthDiv.aDirection == 1 {
                    vOffSet = toY - monthButtonHeight
                }
                else if monthDiv.aDirection == 2 {
                    vOffSet = toY + monthButtonHeight
                }
            }
            else {
                monthButton.visible = false
                continue
            }
        }
        else {
            vOffSet = toY
        }
        if (i + 1) % 4 == 0 {
            let dp = FCPoint(x:left, y:top + vOffSet)
            let ds = FCSize(cx:width - left, cy:dheight)
            let bounds = FCRect(left:dp.x, top:dp.y, right:dp.x + ds.cx, bottom:dp.y + ds.cy)
            monthButton.bounds = bounds
            left = 0
            if i != 0 && i != buttonSize - 1 {
                top += dheight
            }
        }
        else {
            let dp = FCPoint(x:left, y:top + vOffSet)
            //let ds = FCSize(width / 4 + ((i + 1) % 4) % 2, dheight)
            let ds = FCSize(cx:width / 4, cy:dheight)
            let bounds = FCRect(left:dp.x, top:dp.y, right:dp.x + ds.cx, bottom:dp.y + ds.cy)
            monthButton.bounds = bounds
            left += ds.cx
        }
    }
}

/*
* 重置年层布局
* calendar:日历
* yearDiv:年层
* state:状态
*/
func resetYearDiv(calendar:FCCalendar, yearDiv:YearDiv, state:Int) {
    var thisStartYear = yearDiv.startYear
    var lastStartYear = yearDiv.startYear - 12
    var nextStartYear = yearDiv.startYear + 12
    var left = 0.0
    let headHeight = calendar.getHeadDiv().bounds.bottom
    var top = headHeight
    let width = calendar.size.cx
    var height = calendar.size.cy
    height -= calendar.getTimeDiv().bounds.bottom - calendar.getTimeDiv().bounds.top
    var yearButtonHeight = height - top
    if yearButtonHeight < 1 {
        yearButtonHeight = 1
    }
    var toY = 0.0
    var yearButtons = [YearButton]()
    if yearDiv.aDirection == 1 {
        toY = yearButtonHeight * Double(yearDiv.aTick) / Double(yearDiv.aTotalTick)
        if state == 1 {
            thisStartYear = nextStartYear
            lastStartYear = thisStartYear - 12
            nextStartYear = thisStartYear + 12
        }
    }
    else if yearDiv.aDirection == 2 {
        toY = -yearButtonHeight * Double(yearDiv.aTick) / Double(yearDiv.aTotalTick)
        if state == 1 {
            thisStartYear = lastStartYear
            lastStartYear = thisStartYear - 12
            nextStartYear = thisStartYear + 12
        }
    }
    if state == 0 {
        yearButtons = yearDiv.yearButtons
    }
    else if state == 1 {
        yearButtons = yearDiv.yearButtonsAm
    }
    var dheight = yearButtonHeight / 3
    let buttonSize = yearDiv.yearButtons.count
    for i in 0...buttonSize - 1{
        if i == 8 {
            dheight = height - top
        }
        let yearButton = yearButtons[i]
        yearButton.year = thisStartYear + i
        var vOffSet = 0.0
        if state == 1{
            if yearDiv.aTick > 0 {
                yearButton.visible = true
                if yearDiv.aDirection == 1 {
                    vOffSet = toY - yearButtonHeight
                }
                else if yearDiv.aDirection == 2 {
                    vOffSet = toY + yearButtonHeight
                }
            }
            else {
                yearButton.visible = false
                continue
            }
        }
        else {
            vOffSet = toY
        }
        if (i + 1) % 4 == 0 {
            let dp = FCPoint(x:left, y:top + vOffSet)
            let ds = FCSize(cx:width - left, cy:dheight)
            let bounds = FCRect(left:dp.x, top:dp.y, right:dp.x + ds.cx, bottom:dp.y + ds.cy)
            yearButton.bounds = bounds
            left = 0
            if i != 0 && i != buttonSize - 1 {
                top += dheight
            }
        }
        else {
            let dp = FCPoint(x:left, y:top + vOffSet)
            //let ds = FCSize(width / 4 + ((i + 1) % 4) % 2, dheight)
            let ds = FCSize(cx:width / 4, cy:dheight)
            let bounds = FCRect(left:dp.x, top:dp.y, right:dp.x + ds.cx, bottom:dp.y + ds.cy)
            yearButton.bounds = bounds
            left += ds.cx
        }
    }
}

/*
* 选择开始年份
* calendar:日历
* yearDiv:年层
* startYear:开始年
*/
func selectStartYear(calendar:FCCalendar, yearDiv:YearDiv, startYear:Int) {
    if yearDiv.startYear != startYear {
        if startYear > yearDiv.startYear {
            yearDiv.aDirection = 1
        }
        else {
            yearDiv.aDirection = 2
        }
        if calendar.useAnimation {
            yearDiv.aTick = yearDiv.aTotalTick
        }
        yearDiv.startYear = startYear
    }
}

/*
* 选择年份
* calendar:日历
* monthDiv:月层
* year:年
*/
func selectYear(calendar:FCCalendar, monthDiv:MonthDiv, year:Int) {
    if monthDiv.year != year {
        if year > monthDiv.year {
            monthDiv.aDirection = 1
        }
        else {
            monthDiv.aDirection = 2
        }
        if calendar.useAnimation {
            monthDiv.aTick = monthDiv.aTotalTick
        }
        monthDiv.year = year
    }
}

/*
* 选中日期
* calendar:日历
* dayDiv:日期层
* selectedDay:选中日
* lastDay:上一日
*/
func selectDay(calendar:FCCalendar, dayDiv:DayDiv, selectedDay:CDay, lastDay:CDay) {
    if let m = getYear(years:&calendar.years, year:selectedDay.year).months[selectedDay.month]{
        if let thisMonth = getYear(years:&calendar.years, year:lastDay.year).months[lastDay.month]{
            if m != thisMonth {
                if thisMonth.year * 12 + thisMonth.month > m.year * 12 + m.month {
                    dayDiv.aDirection = 2
                }
                else {
                    dayDiv.aDirection = 1
                }
                var buttonSize = dayDiv.dayButtons.count
                for i in 0...buttonSize - 1{
                    let dayButton = dayDiv.dayButtons[i]
                    if (dayDiv.aDirection == 1 && dayButton.getDay() == thisMonth.days[0])
                            || (dayDiv.aDirection == 2 && dayButton.getDay() == thisMonth.days[thisMonth.days.count - 1]) {
                        dayDiv.aClickRowFrom = Int(i / 7)
                        if i % 7 != 0 {
                            dayDiv.aClickRowFrom += 1
                        }
                    }
                }
                resetDayDiv(calendar:calendar, dayDiv:dayDiv, state:0)
                buttonSize = dayDiv.dayButtonsAm.count
                for i in 0...buttonSize - 1{
                    let dayFCButtonm = dayDiv.dayButtonsAm[i]
                    if (dayDiv.aDirection == 1 && dayFCButtonm.getDay() == m.days[0])
                        || (dayDiv.aDirection == 2 && dayFCButtonm.getDay() == m.days[m.days.count - 1]) {
                        dayDiv.aClickRowTo = Int(i / 7)
                        if i % 7 != 0 {
                            dayDiv.aClickRowTo += 1
                        }
                    }
                }

                if calendar.useAnimation {
                    dayDiv.aTick = dayDiv.aTotalTick
                }
            } else {
                let dayButtonsSize = dayDiv.dayButtons.count
                for i in 0...dayButtonsSize - 1{
                    let dayButton = dayDiv.dayButtons[i]
                    if dayButton.getDay() != selectedDay {
                        dayButton.selected = false
                    }
                }
            }
        }
    }
}

/*
* 日历的秒表
* calendar:日历
*/
func calendarTimer(calendar:FCCalendar) {
    var paint = false
    if calendar.getDayDiv().aTick > 0 {
        calendar.getDayDiv().aTick = calendar.getDayDiv().aTick * 2 / 3
        paint = true
    }
    if calendar.getMonthDiv().aTick > 0 {
        calendar.getMonthDiv().aTick = calendar.getMonthDiv().aTick * 2 / 3
        paint = true
    }
    if calendar.getYearDiv().aTick > 0 {
        calendar.getYearDiv().aTick = calendar.getYearDiv().aTick * 2 / 3
        paint = true
    }
    if paint {
        updateCalendar(calendar:calendar)
        invalidateView(view:calendar)
    }
}

/*
* 更新日历的布局
* calendar:日历
*/
func updateCalendar(calendar:FCCalendar) {
    calendar.getHeadDiv().bounds = FCRect(left:0, top:0, right:calendar.size.cx, bottom:80)
    if calendar.mode == "day" {
        resetDayDiv(calendar:calendar, dayDiv:calendar.getDayDiv(), state:0)
        resetDayDiv(calendar:calendar, dayDiv:calendar.getDayDiv(), state:1)
    } else if calendar.mode == "month" {
        resetMonthDiv(calendar:calendar, monthDiv:calendar.getMonthDiv(), state:0)
        resetMonthDiv(calendar:calendar, monthDiv:calendar.getMonthDiv(), state:1)
    }
    else if calendar.mode == "year" {
        resetYearDiv(calendar:calendar, yearDiv:calendar.getYearDiv(), state:0)
        resetYearDiv(calendar:calendar, yearDiv:calendar.getYearDiv(), state:1)
    }
}

/*
* 绘制头部层
* calendar:日历
* headDiv:头部层
* paint:绘图对象
*/
func drawHeadDiv(calendar:FCCalendar, headDiv:HeadDiv, paint:FCPaint) {
    let bounds = headDiv.bounds
    if headDiv.backColor != "none" {
        paint.fillRect(color:headDiv.backColor, left:bounds.left, top:bounds.top, right:bounds.right, bottom:bounds.bottom)
    }
    var weekStrings = [String]()
    weekStrings.append("周日")
    weekStrings.append("周一")
    weekStrings.append("周二")
    weekStrings.append("周三")
    weekStrings.append("周四")
    weekStrings.append("周五")
    weekStrings.append("周六")
    let w = bounds.right - bounds.left
    var left = bounds.left
    for i in 0...6{
        let weekDaySize = paint.textSize(text:weekStrings[i], font:headDiv.weekFont)
        let textX = left + (w / 7) / 2 - weekDaySize.cx / 2
        let textY = bounds.bottom - weekDaySize.cy - 2
        paint.drawText(text:weekStrings[i], color:headDiv.textColor, font:headDiv.weekFont, x:textX, y:textY)
        left += w / 7
    }
    var drawTitle = ""
    if calendar.mode == "day" {
        drawTitle = String(calendar.getSelectedDay().year) + "年" + String(calendar.getSelectedDay().month) + "月"
    } else if calendar.mode == "month" {
        drawTitle = String(calendar.getMonthDiv().year) + "年"
    } else {
        drawTitle = String(calendar.getYearDiv().startYear) + "年-" + String((calendar.getYearDiv().startYear + 11)) + "年"
    }
    let tSize = paint.textSize(text:drawTitle, font:headDiv.titleFont)
    paint.drawText(text:drawTitle, color:headDiv.textColor, font:headDiv.titleFont, x:bounds.left + (w - tSize.cx) / 2, y:30)
    let tR = 10.0
    //画左右三角
    paint.beginPath()
    paint.addLine(x1:5, y1:bounds.top + (bounds.bottom - bounds.top) / 2, x2:5 + tR * 2, y2:bounds.top + (bounds.bottom - bounds.top) / 2 - tR)
    paint.addLine(x1:5 + tR * 2, y1:bounds.top + (bounds.bottom - bounds.top) / 2 - tR, x2:5 + tR * 2, y2:bounds.top + (bounds.bottom - bounds.top) / 2 + tR)
    paint.addLine(x1:5 + tR * 2, y1:bounds.top + (bounds.bottom - bounds.top) / 2 + tR, x2:5.0, y2:bounds.top + (bounds.bottom - bounds.top) / 2)
    paint.fillPath(color:headDiv.arrowColor)
    paint.closePath()

    paint.beginPath()
    paint.addLine(x1:bounds.right - 5, y1:bounds.top + (bounds.bottom - bounds.top) / 2, x2:bounds.right - 5 - tR * 2, y2:bounds.top + (bounds.bottom - bounds.top) / 2 - tR)
    paint.addLine(x1:bounds.right - 5 - tR * 2, y1:bounds.top + (bounds.bottom - bounds.top) / 2 - tR, x2:bounds.right - 5 - tR * 2, y2:bounds.top + (bounds.bottom - bounds.top) / 2 + tR)
    paint.addLine(x1:bounds.right - 5 - tR * 2, y1:bounds.top + (bounds.bottom - bounds.top) / 2 + tR, x2:bounds.right - 5, y2:bounds.top + (bounds.bottom - bounds.top) / 2)
    paint.fillPath(color:headDiv.arrowColor)
    paint.closePath()
}

/*
* 绘制日的按钮
* calendar:日历
* dayButton:日期按钮
* paint:绘图对象
*/
func drawDayButton(calendar:FCCalendar, dayButton:DayButton, paint:FCPaint) {
    if dayButton.getDay().isNotEmpty {
        let bounds = dayButton.bounds
        let text = String(dayButton.getDay().day)
        if dayButton.backColor != "none" {
            paint.fillRect(color:dayButton.backColor, left:bounds.left + 2, top:bounds.top + 2, right:bounds.right - 2, bottom:bounds.bottom - 2)
        }
        if dayButton.inThisMonth {
            paint.drawText(text:text, color:dayButton.textColor, font:dayButton.font, x:bounds.left + 5, y:bounds.top + 7)
        } else {
            paint.drawText(text:text, color:dayButton.textColor2, font:dayButton.font, x:bounds.left + 5, y:bounds.top + 7)
        }
        if dayButton.borderColor != "none" {
            paint.drawRect(color:dayButton.borderColor, width:1, style:[], left:bounds.left + 2, top:bounds.top + 2, right:bounds.right - 2, bottom:bounds.bottom - 2)
        }
    }
}

/*
* 绘制月的按钮
* calendar:日历
* monthButton:月按钮
* paint:绘图对象
*/
func drawMonthButton(calendar:FCCalendar, monthButton:MonthButton, paint:FCPaint) {
    let bounds = monthButton.bounds
    let text = getMonthStr(month:monthButton.month)
    if monthButton.backColor != "none" {
        paint.fillRect(color:monthButton.backColor, left:bounds.left + 2, top:bounds.top + 2, right:bounds.right - 2, bottom:bounds.bottom - 2)
    }
    paint.drawText(text:text, color:monthButton.textColor, font:monthButton.font, x:bounds.left + 5, y:bounds.top + 7)
    if monthButton.borderColor != "none" {
        paint.drawRect(color:monthButton.borderColor, width:1, style:[], left:bounds.left + 2, top:bounds.top + 2, right:bounds.right - 2, bottom:bounds.bottom - 2)
    }
}

/*
* 绘制年的按钮
* calendar:日历
* yearButton:年按钮
* paint:绘图对象
*/
func drawYearButton(calendar:FCCalendar, yearButton:YearButton, paint:FCPaint) {
    let bounds = yearButton.bounds
    let text = String(yearButton.year)
    if yearButton.backColor != "none" {
        paint.fillRect(color:yearButton.backColor, left:bounds.left + 2, top:bounds.top + 2, right:bounds.right - 2, bottom:bounds.bottom - 2)
    }
    paint.drawText(text:text, color:yearButton.textColor, font:yearButton.font, x:bounds.left + 5, y:bounds.top + 7)
    if yearButton.borderColor != "none" {
        paint.drawRect(color:yearButton.borderColor, width:1, style:[], left:bounds.left + 2, top:bounds.top + 2, right:bounds.right - 2, bottom:bounds.bottom - 2)
    }
}

/*
* 绘制日历
* calendar:日历
* paint:绘图对象
*/
func drawCalendar(calendar:FCCalendar, paint:FCPaint) {
    if calendar.backColor != "none" {
        paint.fillRect(color:calendar.backColor, left:0, top:0, right:calendar.size.cx, bottom:calendar.size.cy)
    }
    if calendar.mode == "day"{
        let dayButtonsSize = calendar.getDayDiv().dayButtons.count
        for i in 0...dayButtonsSize - 1{
            let dayButton = calendar.getDayDiv().dayButtons[i]
            if dayButton.visible {
                if calendar.hasPaintCalendarDayButtonEvent{
                    calendar.onPaintCalendarDayButton(calendar, dayButton, paint)
                }
                else if paint.hasPaintCalendarDayButtonEvent{
                    paint.onPaintCalendarDayButton(calendar, dayButton, paint)
                }else{
                    drawDayButton(calendar:calendar, dayButton:dayButton, paint:paint)
                }
            }
        }
        let dayFCButtonmSize = calendar.getDayDiv().dayButtonsAm.count
        for i in 0...dayFCButtonmSize - 1{
            let dayButton = calendar.getDayDiv().dayButtonsAm[i]
            if dayButton.visible {
                if calendar.hasPaintCalendarDayButtonEvent{
                    calendar.onPaintCalendarDayButton(calendar, dayButton, paint)
                }
                else if paint.hasPaintCalendarDayButtonEvent{
                    paint.onPaintCalendarDayButton(calendar, dayButton, paint)
                }else{
                    drawDayButton(calendar:calendar, dayButton:dayButton, paint:paint)
                }
            }
        }
    }
    else if calendar.mode == "month" {
        let monthButtonsSize = calendar.getMonthDiv().monthButtons.count
        for i in 0...monthButtonsSize - 1{
            let monthButton = calendar.getMonthDiv().monthButtons[i]
            if monthButton.visible {
                if calendar.hasPaintCalendarMonthButtonEvent{
                    calendar.onPaintCalendarMonthButton(calendar, monthButton, paint)
                }
                else if paint.hasPaintCalendarMonthButtonEvent{
                    paint.onPaintCalendarMonthButton(calendar, monthButton, paint)
                }else{
                    drawMonthButton(calendar:calendar, monthButton:monthButton, paint:paint)
                }
            }
        }
        let monthFCButtonmSize = calendar.getMonthDiv().monthButtonsAm.count
        for i in 0...monthFCButtonmSize - 1{
            let monthButton = calendar.getMonthDiv().monthButtonsAm[i]
            if monthButton.visible {
                if calendar.hasPaintCalendarMonthButtonEvent{
                    calendar.onPaintCalendarMonthButton(calendar, monthButton, paint)
                }
                else if paint.hasPaintCalendarMonthButtonEvent{
                    paint.onPaintCalendarMonthButton(calendar, monthButton, paint)
                }else{
                    drawMonthButton(calendar:calendar, monthButton:monthButton, paint:paint)
                }
            }
        }
    } else if calendar.mode == "year" {
        let yearButtonsSize = calendar.getYearDiv().yearButtons.count
        for i in 0...yearButtonsSize - 1{
            let yearButton = calendar.getYearDiv().yearButtons[i]
            if yearButton.visible {
                if calendar.hasPaintCalendarYearButtonEvent{
                    calendar.onPaintCalendarYearButton(calendar, yearButton, paint)
                }
                else if paint.hasPaintCalendarYearButtonEvent{
                    paint.onPaintCalendarYearButton(calendar, yearButton, paint)
                }else{
                    drawYearButton(calendar:calendar, yearButton:yearButton, paint:paint)
                }
            }
        }
        let yearFCButtonmSize = calendar.getYearDiv().yearButtonsAm.count
        for i in 0...yearFCButtonmSize - 1{
            let yearButton = calendar.getYearDiv().yearButtonsAm[i]
            if yearButton.visible {
                if calendar.hasPaintCalendarYearButtonEvent{
                    calendar.onPaintCalendarYearButton(calendar, yearButton, paint)
                }
                else if paint.hasPaintCalendarYearButtonEvent{
                    paint.onPaintCalendarYearButton(calendar, yearButton, paint)
                }else{
                    drawYearButton(calendar:calendar, yearButton:yearButton, paint:paint)
                }
            }
        }
    }
    if calendar.hasPaintCalendarHeadDivEvent{
        calendar.onPaintCalendarHeadDiv(calendar, calendar.getHeadDiv(), paint)
    }
    else if paint.hasPaintCalendarHeadDivEvent{
        paint.onPaintCalendarHeadDiv(calendar, calendar.getHeadDiv(), paint)
    }else{
        drawHeadDiv(calendar:calendar, headDiv:calendar.getHeadDiv(), paint:paint)
    }
    if calendar.borderColor != "none" {
        paint.drawRect(color:calendar.borderColor, width:1, style:[], left:0, top:0, right:calendar.size.cx, bottom:calendar.size.cy)
    }
}

/*
* 点击日的按钮
* calendar:日历
* dayButton:日期按钮
* mp:坐标
*/
func clickDayButton(calendar:FCCalendar, dayButton:DayButton, mp:FCPoint) {
    let lastDay = calendar.getSelectedDay()
    calendar.setSelectedDay(d:dayButton.getDay())
    selectDay(calendar:calendar, dayDiv:calendar.getDayDiv(), selectedDay:calendar.getSelectedDay(), lastDay:lastDay)
    updateCalendar(calendar:calendar)
    invalidateView(view:calendar)
}

/*
* 点击月的按钮
* calendar:日历
* monthButton:月按钮
* mp:坐标
*/
func clickMonthButton(calendar:FCCalendar, monthButton:MonthButton, mp:FCPoint) {
    if let month = getYear(years:&calendar.years, year:monthButton.year).months[monthButton.month]{
        calendar.mode = "day"
        let lastDay = calendar.getSelectedDay()
        if let dDay = month.days[1]{
            calendar.setSelectedDay(d:dDay)
            selectDay(calendar:calendar, dayDiv:calendar.getDayDiv(), selectedDay:calendar.getSelectedDay(), lastDay:lastDay)
            updateCalendar(calendar:calendar)
            invalidateView(view:calendar)
        }
    }
}

/*
* 点击年的按钮
* calendar:日历
* yearButton:年按钮
* mp:坐标
*/
func clickYearButton(calendar:FCCalendar, yearButton:YearButton, mp:FCPoint) {
    calendar.mode = "month"
    selectYear(calendar:calendar, monthDiv: calendar.getMonthDiv(), year:yearButton.year)
    updateCalendar(calendar:calendar)
    invalidateView(view:calendar)
}

/*
* 点击左侧的按钮
* calendar:日历
* headDiv:头部层
* mp:坐标
*/
func clickLastButton(calendar:FCCalendar, headDiv:HeadDiv, mp:FCPoint) {
    if calendar.mode == "day" {
        let lastMonth = getLastMonth(calendar:calendar, year:calendar.getSelectedDay().year, month:calendar.getSelectedDay().month)
        let lastDay = calendar.getSelectedDay()
        if let dDay = lastMonth.days[1]{
            calendar.setSelectedDay(d:dDay)
            selectDay(calendar:calendar, dayDiv:calendar.getDayDiv(), selectedDay:calendar.getSelectedDay(), lastDay:lastDay)
            updateCalendar(calendar:calendar)
            invalidateView(view:calendar)
        }
    } else if calendar.mode == "month" {
        var year = calendar.getMonthDiv().year
        year -= 1
        selectYear(calendar:calendar, monthDiv:calendar.getMonthDiv(), year:year)
        updateCalendar(calendar:calendar)
        invalidateView(view:calendar)
    } else if calendar.mode == "year"{
        var year = calendar.getYearDiv().startYear
        year -= 12
        selectStartYear(calendar:calendar, yearDiv:calendar.getYearDiv(), startYear:year)
        updateCalendar(calendar:calendar)
        invalidateView(view:calendar)
    }
}

/*
* 点击右侧的按钮
* calendar:日历
* headDiv:头部层
* mp:坐标
*/
func clickNextButton(calendar:FCCalendar, headDiv:HeadDiv, mp:FCPoint) {
    if calendar.mode == "day" {
        let nextMonth = getNextMonth(calendar:calendar, year:calendar.getSelectedDay().year, month:calendar.getSelectedDay().month)
        let lastDay = calendar.getSelectedDay()
        if let dDay = nextMonth.days[1]{
            calendar.setSelectedDay(d:dDay)
            selectDay(calendar:calendar, dayDiv:calendar.getDayDiv(), selectedDay:calendar.getSelectedDay(), lastDay:lastDay)
            updateCalendar(calendar:calendar)
            invalidateView(view:calendar)
        }
    } else if calendar.mode == "month" {
        var year = calendar.getMonthDiv().year
        year += 1
        selectYear(calendar:calendar, monthDiv:calendar.getMonthDiv(), year:year)
        updateCalendar(calendar:calendar)
        invalidateView(view:calendar)
    } else if calendar.mode == "year" {
        var year = calendar.getYearDiv().startYear
        year += 12
        selectStartYear(calendar:calendar, yearDiv:calendar.getYearDiv(), startYear:year)
        updateCalendar(calendar:calendar)
        invalidateView(view:calendar)
    }
}

/*
* 改变模式的按钮
* calendar:日历
* headDiv:头部层
* mp:坐标
*/
func clickModeButton(calendar:FCCalendar, headDiv:HeadDiv, mp:FCPoint) {
    if calendar.mode == "day" {
        calendar.mode = "month"
        calendar.getMonthDiv().month = calendar.getSelectedDay().month
        calendar.getMonthDiv().year = calendar.getSelectedDay().year
        updateCalendar(calendar:calendar)
        invalidateView(view:calendar)
    }
    else if calendar.mode == "month" {
        calendar.mode = "year"
        selectStartYear(calendar:calendar, yearDiv:calendar.getYearDiv(), startYear:calendar.getMonthDiv().year)
        updateCalendar(calendar:calendar)
        invalidateView(view:calendar)
    }
}

/*
* 点击日历
* calendar:日历
* mp:坐标
*/
func clickCalendar(calendar:FCCalendar, mp:FCPoint) {
    let headBounds = calendar.getHeadDiv().bounds
    if mp.x >= headBounds.left && mp.x <= headBounds.right && mp.y >= headBounds.top && mp.y <= headBounds.bottom {
        let tR:Double = 10
        if mp.x < headBounds.left + tR * 3 {
            clickLastButton(calendar:calendar, headDiv:calendar.getHeadDiv(), mp:mp)
            return
        } else if mp.x > headBounds.right - tR * 3 {
            clickNextButton(calendar:calendar, headDiv:calendar.getHeadDiv(), mp:mp)
            return
        } else {
            clickModeButton(calendar:calendar, headDiv:calendar.getHeadDiv(), mp:mp)
            return
        }
    }
    if calendar.mode == "day" {
        let dayButtonsSize = calendar.getDayDiv().dayButtons.count
        for i in 0...dayButtonsSize - 1{
            let dayButton = calendar.getDayDiv().dayButtons[i]
            if dayButton.visible {
                let bounds = dayButton.bounds
                if mp.x >= bounds.left && mp.x <= bounds.right && mp.y >= bounds.top && mp.y <= bounds.bottom {
                    clickDayButton(calendar:calendar, dayButton:dayButton, mp:mp)
                    return
                }
            }
        }
    }
    else if calendar.mode == "month" {
        let monthButtonsSize = calendar.getMonthDiv().monthButtons.count
        for i in 0...monthButtonsSize - 1{
            let monthButton = calendar.getMonthDiv().monthButtons[i]
            if monthButton.visible {
                let bounds = monthButton.bounds
                if mp.x >= bounds.left && mp.x <= bounds.right && mp.y >= bounds.top && mp.y <= bounds.bottom {
                    clickMonthButton(calendar:calendar, monthButton:monthButton, mp:mp)
                    return
                }
            }
        }
    } else if calendar.mode == "year" {
        let yearButtonsSize = calendar.getYearDiv().yearButtons.count
        for i in 0...yearButtonsSize - 1{
            let yearButton = calendar.getYearDiv().yearButtons[i]
            if yearButton.visible {
                let bounds = yearButton.bounds
                if mp.x >= bounds.left && mp.x <= bounds.right && mp.y >= bounds.top && mp.y <= bounds.bottom {
                    clickYearButton(calendar:calendar, yearButton:yearButton, mp:mp)
                    return
                }
            }
        }
    }
}

/*
* 绘制滚动条
* div:图层
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawDivScrollBar(div:FCDiv, paint:FCPaint, clipRect:FCRect) {
    div.hScrollIsVisible = false
    div.vScrollIsVisible = false
    //绘制滚动条
    if div.showHScrollBar {
        let contentWidth = getDivContentWidth(div:div)
        if contentWidth > 0 && contentWidth > 0 && contentWidth > div.size.cx {
            let sLeft = div.scrollH / contentWidth * div.size.cx
            var sRight = (div.scrollH + div.size.cx) / contentWidth * div.size.cx
            if sRight - sLeft < div.scrollSize {
                sRight = sLeft + div.scrollSize
            }
            if paint.getTouchMoveView() == div && (div.hoverScrollHButton || div.downScrollHButton) {
                paint.fillRect(color:div.scrollBarHoveredColor, left:sLeft, top:div.size.cy - div.scrollSize, right:sRight, bottom:div.size.cy)
            } else {
                paint.fillRect(color:div.scrollBarColor, left:sLeft, top:div.size.cy - div.scrollSize, right:sRight, bottom:div.size.cy)
            }
            div.hScrollIsVisible = true
        }
    }
    if div.showVScrollBar {
        let contentHeight = getDivContentHeight(div:div)
        if contentHeight > 0 && contentHeight > 0 && contentHeight > div.size.cy {
            let sTop = div.scrollV / contentHeight * div.size.cy
            var sBottom = sTop + (div.size.cy / contentHeight * div.size.cy)
            if sBottom - sTop < div.scrollSize {
                sBottom = sTop + div.scrollSize
            }
            if paint.getTouchMoveView() == div && (div.hoverScrollVButton || div.downScrollVButton) {
                paint.fillRect(color:div.scrollBarHoveredColor, left:div.size.cx - div.scrollSize, top:sTop, right:div.size.cx, bottom:sBottom)
            } else {
                paint.fillRect(color:div.scrollBarColor, left:div.size.cx - div.scrollSize, top:sTop, right:div.size.cx, bottom:sBottom)
            }
            div.vScrollIsVisible = true
        }
    }
}

/*
* 获取内容的宽度
* div:图层
*/
func getDivContentWidth(div:FCView)->Double {
    var cWidth:Double = 0
    if div.views.count > 0 {
        for i in 0...div.views.count - 1{
            if div.views[i].visible {
                if cWidth < div.views[i].location.x + div.views[i].size.cx {
                    cWidth = div.views[i].location.x + div.views[i].size.cx
                }
            }
        }
    }
    return cWidth
}

/*
* 获取内容的高度
* div:图层
*/
func getDivContentHeight(div:FCView)->Double {
    var cHeight:Double = 0
    if div.views.count > 0 {
        for i in 0...div.views.count - 1{
            if div.views[i].visible{
                if cHeight < div.views[i].location.y + div.views[i].size.cy {
                    cHeight = div.views[i].location.y + div.views[i].size.cy
                }
            }
        }
    }
    return cHeight
}

/*
* 图层的鼠标移动方法
* div: 图层
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
*/
func touchMoveDiv(div:FCDiv, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint) {
    div.hoverScrollHButton = false
    div.hoverScrollVButton = false
    let mp = FCPoint(x:firstPoint.x, y:firstPoint.y)
    if firstTouch {
        if div.showHScrollBar || div.showVScrollBar {
            if div.downScrollHButton {
                let contentWidth = getDivContentWidth(div:div)
                let subX = (mp.x - div.startPoint.x) / div.size.cx * contentWidth
                var newScrollH = div.startScrollH + subX
                if newScrollH < 0 {
                    newScrollH = 0
                } else if newScrollH > contentWidth - div.size.cx {
                    newScrollH = contentWidth - div.size.cx
                }
                div.scrollH = newScrollH
                div.getPaint().cancelClick = true
                return

            } else if div.downScrollVButton {
                let contentHeight = getDivContentHeight(div:div)
                let subY = (mp.y - div.startPoint.y) / div.size.cy * contentHeight
                var newScrollV = div.startScrollV + subY
                if newScrollV < 0 {
                    newScrollV = 0
                } else if newScrollV > contentHeight - div.size.cy {
                    newScrollV = contentHeight - div.size.cy
                }
                div.scrollV = newScrollV
                div.getPaint().cancelClick = true
                return
            }
        }
        if div.allowDragScroll {
            let contentWidth = getDivContentWidth(div:div)
            if contentWidth > div.size.cx {
                let subX = div.startPoint.x - mp.x
                var newScrollH = div.startScrollH + subX
                if newScrollH < 0 {
                    newScrollH = 0
                } else if newScrollH > contentWidth - div.size.cx {
                    newScrollH = contentWidth - div.size.cx
                }
                div.scrollH = newScrollH
                if subX > 5 || subX < -5 {
                    div.getPaint().cancelClick = true
                }
            }
            let contentHeight = getDivContentHeight(div:div)
            if contentHeight > div.size.cy {
                let subY = div.startPoint.y - mp.y
                var newScrollV = div.startScrollV + subY
                if newScrollV < 0 {
                    newScrollV = 0
                } else if newScrollV > contentHeight - div.size.cy {
                    newScrollV = contentHeight - div.size.cy
                }
                div.scrollV = newScrollV
                if subY > 5 || subY < -5 {
                    div.getPaint().cancelClick = true
                }
            }
        }
    } else {
        if div.showHScrollBar {
            let contentWidth = getDivContentWidth(div:div)
            if contentWidth > 0 && contentWidth > 0 && contentWidth > div.size.cx {
                let sLeft = div.scrollH / contentWidth * div.size.cx
                var sRight = (div.scrollH + div.size.cx) / contentWidth * div.size.cx
                if sRight - sLeft < div.scrollSize {
                    sRight = sLeft + div.scrollSize
                }
                if mp.x >= sLeft && mp.x <= sRight && mp.y >= div.size.cy - div.scrollSize && mp.y <= div.size.cy {
                    div.hoverScrollHButton = true
                    return
                } else {
                    div.hoverScrollHButton = false
                }
            }
        }
        if div.showVScrollBar {
            let contentHeight = getDivContentHeight(div:div)
            if contentHeight > 0 && contentHeight > div.size.cy {
                let sTop = div.scrollV / contentHeight * div.size.cy
                var sBottom = (div.scrollV + div.size.cy) / contentHeight * div.size.cy
                if sBottom - sTop < div.scrollSize {
                    sBottom = sTop + div.scrollSize
                }
                if mp.x >= div.size.cx - div.scrollSize && mp.x <= div.size.cx && mp.y >= sTop && mp.y <= sBottom {
                    div.hoverScrollVButton = true
                    return
                } else {
                    div.hoverScrollVButton = false
                }
            }
        }
    }
}

/*
* 图层的鼠标按下方法
* div: 图层
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
* clicks:点击次数
*/
func touchDownDiv(div:FCDiv, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint, clicks:Int) {
    let mp = FCPoint(x:firstPoint.x, y:firstPoint.y)
    div.startPoint = mp
    div.touchDownTime = getTickCount()
    div.downScrollHButton = false
    div.downScrollVButton = false
    div.hoverScrollHButton = false
    div.hoverScrollVButton = false
    div.scrollAddSpeed = 0
    div.isScrolling = false
    if div.showHScrollBar {
        let contentWidth = getDivContentWidth(div:div)
        if contentWidth > 0 && contentWidth > div.size.cx {
            let sLeft = div.scrollH / contentWidth * div.size.cx
            var sRight = (div.scrollH + div.size.cx) / contentWidth * div.size.cx
            if sRight - sLeft < div.scrollSize{
                sRight = sLeft + div.scrollSize
            }
            if mp.x >= sLeft && mp.x <= sRight && mp.y >= div.size.cy - div.scrollSize && mp.y <= div.size.cy {
                div.downScrollHButton = true
                div.startScrollH = div.scrollH
                return
            }
        }
    }
    if div.showVScrollBar {
        let contentHeight = getDivContentHeight(div:div)
        if contentHeight > 0 && contentHeight > div.size.cy {
            let sTop = div.scrollV / contentHeight * div.size.cy
            var sBottom = (div.scrollV + div.size.cy) / contentHeight * div.size.cy
            if sBottom - sTop < div.scrollSize {
                sBottom = sTop + div.scrollSize
            }
            if mp.x >= div.size.cx - div.scrollSize && mp.x <= div.size.cx && mp.y >= sTop && mp.y <= sBottom {
                div.downScrollVButton = true
                div.startScrollV = div.scrollV
                return
            }
        }
    }
    if div.allowDragScroll {
        div.startScrollH = div.scrollH
        div.startScrollV = div.scrollV
    }
}

/*
* 图层的鼠标抬起方法
* div: 图层
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
* clicks:点击次数
*/
func touchUpDiv(div:FCDiv, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint, clicks:Int) {
    div.hoverScrollHButton = false
    div.hoverScrollVButton = false
    if firstTouch {
        if div.allowDragScroll {
            let touchUpTime = getTickCount()
            let diff = Double(touchUpTime - div.touchDownTime)
            //加速滚动
            if diff > 0 && diff < 250{
                let sub1 = Int(30 * ((abs(firstPoint.y - div.startPoint.y)) / 20) / diff * 10)
                let sub2 = Int(30 * ((abs(firstPoint.x - div.startPoint.x)) / 20) / diff * 10)
                if abs(sub1) > abs(sub2) {
                    if firstPoint.y < div.startPoint.y {
                        div.scrollAddSpeed += sub1
                    } else {
                        div.scrollAddSpeed -= sub1
                    }
                    div.scrollDirection = 0
                } else {
                    if firstPoint.x < div.startPoint.x {
                        div.scrollAddSpeed += sub2
                    } else {
                        div.scrollAddSpeed -= sub2
                    }
                    div.scrollDirection = 1
                }
                div.isScrolling = true
                if abs(div.scrollAddSpeed) > 0 {
                    div.getPaint().cancelClick = true
                }
            }
        }
    }
    div.downScrollHButton = false
    div.downScrollVButton = false
}

/*
* 图层的鼠标滚轮方法
* div:图层
* delta:滚轮值
*/
func touchWheelDiv(div:FCDiv, delta:Int) {
    var oldScrollV = div.scrollV
    if delta > 0 {
        oldScrollV -= 10
    } else if (delta < 0) {
        oldScrollV += 10
    }
    let contentHeight = getDivContentHeight(div:div)
    if contentHeight < div.size.cy {
        div.scrollV = 0
    } else {
        if oldScrollV < 0 {
            oldScrollV = 0
        } else if oldScrollV > contentHeight - div.size.cy {
            oldScrollV = contentHeight - div.size.cy
        }
        div.scrollV = oldScrollV
    }
}

/*
* 重绘图层
* div:视图
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawDiv(div:FCView, paint:FCPaint, clipRect:FCRect) {
    if div.backColor != "none" {
        paint.fillRoundRect(color:div.backColor, left:0, top:0, right:div.size.cx, bottom:div.size.cy, cornerRadius: div.cornerRadius)
    }
}

/*
* 重绘图层边线
* div:视图
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawDivBorder(div:FCView, paint:FCPaint, clipRect:FCRect) {
    if div.borderColor != "none" {
        paint.drawRoundRect(color:div.borderColor, width:div.borderWidth, style:[], left:0, top:0, right:div.size.cx, bottom:div.size.cy, cornerRadius: div.cornerRadius)
    }
}

/*
 * 检查图层滚动
 * div:图层
 */
func checkDivScroll(div:FCDiv){
    if div.isScrolling{
        var sub = Int(div.scrollAddSpeed / 10)
        if sub == 0 && div.scrollAddSpeed > 1 {
            sub = 1
        } else if sub == 0 && div.scrollAddSpeed < -1 {
            sub = -1
        }
        div.scrollAddSpeed -= sub
        if abs(sub) <= 1 {
            div.scrollAddSpeed = 0
            div.isScrolling = false
            invalidateView(view:div)
        }else {
            var oldScrollV = div.scrollV + Double(div.scrollAddSpeed)
            var oldScrollH = div.scrollH + Double(div.scrollAddSpeed)
            if div.scrollDirection == 0 {
                let contentHeight = getDivContentHeight(div:div)
                if contentHeight < div.size.cy {
                    div.scrollV = 0
                } else {
                    if oldScrollV < 0 {
                        oldScrollV = 0
                    } else if oldScrollV > contentHeight - div.size.cy {
                        oldScrollV = contentHeight - div.size.cy
                    }
                    div.scrollV = oldScrollV
                }
            } else {
                let contentWidth = getDivContentWidth(div:div)
                if contentWidth < div.size.cx {
                    div.scrollH = 0
                } else {
                    if oldScrollH < 0 {
                        oldScrollH = 0
                    } else if oldScrollH > contentWidth - div.size.cx {
                        oldScrollH = contentWidth - div.size.cx
                    }
                    div.scrollH = oldScrollH
                }
            }
            invalidateView(view:div)
        }
    }
}

/*
 * 快速添加表格列
 * grid:表格
 * columns:列名集合
 */
func fastAddGridColumns(grid:FCGrid, columns:[String]){
    let columnsSize = columns.count
    for i in 0...columnsSize - 1{
        let gridColumn = FCGridColumn()
        gridColumn.text = columns[i]
        grid.columns.append(gridColumn)
    }
}

/*
 * 快速添加表格行
 * grid:表格
 * datas:数据集合
 */
func fastAddGridRow(grid:FCGrid, datas:[String])->FCGridRow {
    let gridRow = FCGridRow()
    let datasSize = datas.count
    for i in 0...datasSize - 1{
        let gridCell = FCGridCell()
        gridCell.value = datas[i]
        gridRow.cells.append(gridCell)
    }
    return gridRow
}

/*
 * 添加视图到单元格
 * view:视图
 * cell:单元格
 * grid:表格
 */
func addViewToGridCell(view:FCView, cell:FCGridCell, grid:FCGrid){
    view.displayOffset = false
    view.visible = false
    cell.setView(v: view)
    addViewToParent(view: view, parent: grid)
}

/*
* 绘制单元格
* grid:表格
* row:行
* column:列
* cell:单元格
* paint:绘图对象
* left:左侧坐标
* top:上方坐标
* right:右侧坐标
* bottom:下方坐标
*/
func drawGridCell(grid:FCGrid, row:FCGridRow, column:FCGridColumn, cell:FCGridCell, paint:FCPaint, left:Double, top:Double, right:Double, bottom:Double) {
    if cell.backColor != "none"{
        paint.fillRect(color:cell.backColor, left:left, top:top, right:right, bottom:bottom)
    }
    if row.selected {
        if grid.selectedRowColor != "none" {
            paint.fillRect(color:grid.selectedRowColor, left:left, top:top, right:right, bottom:bottom)
        }
    }
    if cell.borderColor != "none"{
        paint.drawRect(color:cell.borderColor, width:1, style:[], left:left, top:top, right:right, bottom:bottom)
    }
    if cell.value.count > 0 {
        var showText = cell.value
        if column.colType == "double"{
            if cell.digit >= 0{
                showText = toFixed(value: Double(showText)!, digit: cell.digit)
            }
        }
        let tSize = paint.textSize(text:showText, font:cell.font)
        if tSize.cx <= right - left{
            if(column.cellAlign == "left"){
                paint.drawText(text:showText, color:cell.textColor, font:cell.font, x:left + 2, y:top + grid.rowHeight / 2 - tSize.cy / 2)
            }else if column.cellAlign == "center"{
                paint.drawText(text:showText, color:cell.textColor, font:cell.font, x:left + (right - left - tSize.cx) / 2, y:top + grid.rowHeight / 2 - tSize.cy / 2)
            }else if column.cellAlign == "right"{
                paint.drawText(text:showText, color:cell.textColor, font:cell.font, x:right - tSize.cx, y:top + grid.rowHeight / 2 - tSize.cy / 2)
            }
        }else{
            paint.drawTextAutoEllipsis(text: showText, color: cell.textColor, font: cell.font, left: left, top: top + grid.rowHeight / 2 - tSize.cy / 2, right: right, bottom: top + grid.rowHeight / 2 + tSize.cy / 2)
        }
    }
}

/*
* 绘制列
* grid:表格
* column:列
* paint:绘图对象
* left:左侧坐标
* top:上方坐标
* right:右侧坐标
* bottom:下方坐标
*/
func drawGridColumn(grid:FCGrid, column:FCGridColumn, paint:FCPaint, left:Double, top:Double, right:Double, bottom:Double) {
    let tSize = paint.textSize(text:column.text, font:column.font)
    if column.backColor != "none" {
        paint.fillRect(color:column.backColor, left:left, top:top, right:right, bottom:bottom)
    }
    if column.borderColor != "none" {
        paint.drawRect(color:column.borderColor, width:1, style:[], left:left, top:top, right:right, bottom:bottom)
    }
    paint.drawText(text:column.text, color:column.textColor, font:column.font, x:left + (column.width - tSize.cx) / 2, y:top + (grid.headerHeight - tSize.cy) / 2)
    if column.sort == "asc" {
        paint.beginPath()
        let cR = (bottom - top) / 4
        let oX = right - cR * 2, oY = top + (bottom - top) / 2
        paint.addLine(x1:oX, y1:oY - cR, x2:oX - cR, y2:oY + cR)
        paint.addLine(x1:oX - cR, y1:oY + cR, x2:oX + cR, y2:oY + cR)
        paint.addLine(x1:oX + cR, y1:oY + cR, x2:oX, y2:oY - cR)
        paint.fillPath(color:column.textColor)
        paint.closePath()
    }
    else if column.sort == "desc" {
        paint.beginPath()
        let cR = (bottom - top) / 4
        let oX = right - cR * 2, oY = top + (bottom - top) / 2
        paint.addLine(x1:oX, y1:oY + cR, x2:oX - cR, y2:oY - cR)
        paint.addLine(x1:oX - cR, y1:oY - cR, x2:oX + cR, y2:oY - cR)
        paint.addLine(x1:oX + cR, y1:oY - cR, x2:oX, y2:oY + cR)
        paint.fillPath(color:column.textColor)
        paint.closePath()
    }
}

/*
* 绘制表格
* grid:表格
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawGrid(grid:FCGrid, paint:FCPaint, clipRect:FCRect) {
    var cTop = -grid.scrollV + grid.headerHeight
    if grid.views.count > 0{
        for i in 0...grid.views.count - 1{
            grid.views[i].visible = false
        }
    }
    //绘制行
    var colLeft = 0.0
    if grid.columns.count > 0{
        for i in 0...grid.columns.count - 1{
            if grid.columns[i].widthStr.count > 0{
                let newWidthStr = grid.columns[i].widthStr.replacingOccurrences(of: "%", with: "")
                grid.columns[i].width = Double(StringToFloat(str:newWidthStr)) * grid.size.cx / 100
            }
            let colRect = FCRect(left:colLeft, top:0, right:colLeft + grid.columns[i].width, bottom:grid.headerHeight)
            grid.columns[i].bounds = colRect
            grid.columns[i].index = i
            colLeft += grid.columns[i].width
        }
    }
    if grid.rows.count > 0{
        for i in 0...grid.rows.count - 1{
            let row = grid.rows[i]
            row.index = i
            if row.visible {
                let rTop = cTop, rBottom = cTop + grid.rowHeight
                if rBottom >= 0 && cTop <= grid.size.cy {
                    for j in 0...row.cells.count - 1{
                        let cell = row.cells[j]
                        var gridColumn = cell.getColumn()
                        if !gridColumn.isNotEmpty{
                            gridColumn = grid.columns[j]
                        }
                        if gridColumn.visible {
                            if !gridColumn.frozen {
                                var cellWidth = gridColumn.width
                                let colSpan = cell.colSpan
                                if colSpan > 1 {
                                    for n in 1...colSpan - 1{
                                        let spanColumn = grid.columns[gridColumn.index + n]
                                        if spanColumn.isNotEmpty && spanColumn.visible {
                                            cellWidth += spanColumn.width
                                        }
                                    }
                                }
                                var cellHeight = grid.rowHeight
                                let rowSpan = cell.rowSpan
                                if rowSpan > 1 {
                                    for n in 1...rowSpan - 1{
                                        let spanRow = grid.rows[i + n]
                                        if spanRow.isNotEmpty && spanRow.visible {
                                            cellHeight += grid.rowHeight
                                        }
                                    }
                                }
                                let cRect = FCRect(left:gridColumn.bounds.left - grid.scrollH, top:rTop, right:gridColumn.bounds.left + cellWidth - grid.scrollH, bottom:rTop + cellHeight)
                                if cRect.right >= 0 && cRect.left < grid.size.cx {
                                    if grid.hasPaintGridCellEvent{
                                        grid.onPaintGridCell(grid, row, gridColumn, cell, paint, cRect.left, cRect.top, cRect.right, cRect.bottom)
                                    }
                                    else if paint.hasPaintGridCellEvent{
                                        paint.onPaintGridCell(grid, row, gridColumn, cell, paint, cRect.left, cRect.top, cRect.right, cRect.bottom)
                                    }else{
                                        drawGridCell(grid:grid, row:row, column:gridColumn, cell:cell, paint:paint, left:cRect.left, top:cRect.top, right:cRect.right, bottom:cRect.bottom)
                                    }
                                    if cell.view.count > 0{
                                        let cellView = cell.getView()
                                        cellView.visible = true
                                        cellView.location = FCPoint(x:cRect.left + grid.scrollH, y:cRect.top + grid.scrollV)
                                        cellView.size = FCSize(cx:cRect.right - cRect.left, cy:cRect.bottom - cRect.top)
                                    }
                                }
                            }
                        }
                    }
                }
                if rBottom >= 0 && cTop <= grid.size.cy {
                    for j in 0...row.cells.count - 1{
                        let cell = row.cells[j]
                        var gridColumn = cell.getColumn()
                        if !gridColumn.isNotEmpty {
                            gridColumn = grid.columns[j]
                        }
                        if gridColumn.visible {
                            if gridColumn.frozen {
                                var cellWidth = gridColumn.width
                                let colSpan = cell.colSpan
                                if colSpan > 1 {
                                    for n in 1...colSpan - 1{
                                        let spanColumn = grid.columns[gridColumn.index + n]
                                        if spanColumn.isNotEmpty && spanColumn.visible {
                                            cellWidth += spanColumn.width
                                        }
                                    }
                                }
                                var cellHeight = grid.rowHeight
                                let rowSpan = cell.rowSpan
                                if rowSpan > 1 {
                                    for n in 1...rowSpan - 1{
                                        let spanRow = grid.rows[i + n]
                                        if spanRow.isNotEmpty && spanRow.visible {
                                            cellHeight += grid.rowHeight
                                        }
                                    }
                                }
                                let cRect = FCRect(left:gridColumn.bounds.left - grid.scrollH, top:rTop, right:gridColumn.bounds.left + cellWidth - grid.scrollH, bottom:rTop + cellHeight)
                                if cRect.right >= 0 && cRect.left < grid.size.cx {
                                    if grid.hasPaintGridCellEvent{
                                        grid.onPaintGridCell(grid, row, gridColumn, cell, paint, cRect.left, cRect.top, cRect.right, cRect.bottom)
                                    }
                                    else if paint.hasPaintGridCellEvent{
                                        paint.onPaintGridCell(grid, row, gridColumn, cell, paint, cRect.left, cRect.top, cRect.right, cRect.bottom)
                                    }else{
                                        drawGridCell(grid:grid, row:row, column:gridColumn, cell:cell, paint:paint, left:cRect.left, top:cRect.top, right:cRect.right, bottom:cRect.bottom)
                                    }
                                    if cell.view.count > 0{
                                        let cellView = cell.getView()
                                        cellView.visible = true
                                        cellView.location = FCPoint(x:cRect.left + grid.scrollH, y:cRect.top + grid.scrollV)
                                        cellView.size = FCSize(cx:cRect.right - cRect.left, cy:cRect.bottom - cRect.top)
                                    }
                                }
                            }
                        }
                    }
                }
                if cTop > grid.size.cy {
                    break
                }
                cTop += grid.rowHeight
            }
        }
    }
}

/*
* 绘制表格的滚动条
* grid:表格
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawGridScrollBar(grid:FCGrid, paint:FCPaint, clipRect:FCRect) {
    grid.hScrollIsVisible = false
    grid.vScrollIsVisible = false
    if grid.headerHeight > 0 && grid.columns.count > 0 {
        var cLeft = -grid.scrollH
        //绘制列
        for i in 0...grid.columns.count - 1{
            let gridColumn = grid.columns[i]
            if grid.columns[i].visible {
                if !gridColumn.frozen {
                    if grid.hasPaintGridColumnEvent{
                        grid.onPaintGridColumn(grid, grid.columns[i], paint, cLeft, 0, cLeft + gridColumn.width, grid.headerHeight)
                    }
                    else if paint.hasPaintGridColumnEvent{
                        paint.onPaintGridColumn(grid, grid.columns[i], paint, cLeft, 0, cLeft + gridColumn.width, grid.headerHeight)
                    }else{
                        drawGridColumn(grid:grid, column:grid.columns[i], paint:paint, left:cLeft, top:0, right:cLeft + gridColumn.width, bottom:grid.headerHeight)
                    }
                }
                cLeft += gridColumn.width
            }
        }
        cLeft = 0
        for i in 0...grid.columns.count - 1{
            let gridColumn = grid.columns[i]
            if grid.columns[i].visible {
                if gridColumn.frozen {
                    if grid.hasPaintGridColumnEvent{
                        grid.onPaintGridColumn(grid, grid.columns[i], paint, cLeft, 0, cLeft + gridColumn.width, grid.headerHeight)
                    }
                    else if paint.hasPaintGridColumnEvent{
                        paint.onPaintGridColumn(grid, grid.columns[i], paint, cLeft, 0, cLeft + gridColumn.width, grid.headerHeight)
                    }else{
                        drawGridColumn(grid:grid, column:grid.columns[i], paint:paint, left:cLeft, top:0, right:cLeft + gridColumn.width, bottom:grid.headerHeight)
                    }
                }
                cLeft += gridColumn.width
            }
        }
    }
    if grid.showHScrollBar {
        let contentWidth = getGridContentWidth(grid:grid)
        if contentWidth > 0 && contentWidth > grid.size.cx {
            let sLeft = grid.scrollH / contentWidth * grid.size.cx
            var sRight = (grid.scrollH + grid.size.cx) / contentWidth * grid.size.cx
            if sRight - sLeft < grid.scrollSize {
                sRight = sLeft + grid.scrollSize
            }
            if grid.getPaint().getTouchMoveView() == grid && (grid.hoverScrollHButton || grid.downScrollHButton){
                paint.fillRect(color:grid.scrollBarHoveredColor, left:sLeft, top:grid.size.cy - grid.scrollSize, right:sRight, bottom:grid.size.cy)
            } else {
                paint.fillRect(color:grid.scrollBarColor, left:sLeft, top:grid.size.cy - grid.scrollSize, right:sRight, bottom:grid.size.cy)
            }
            grid.hScrollIsVisible = true
        }
    }
    if grid.showVScrollBar {
        let contentHeight = getGridContentHeight(grid:grid)
        if contentHeight > 0 && contentHeight > grid.size.cy - grid.headerHeight {
            let sTop = grid.headerHeight + grid.scrollV / contentHeight * (grid.size.cy - grid.headerHeight - grid.scrollSize)
            var sBottom = sTop + ((grid.size.cy - grid.headerHeight - grid.scrollSize)) / contentHeight * (grid.size.cy - grid.headerHeight - grid.scrollSize)
            if (sBottom - sTop < grid.scrollSize) {
                sBottom = sTop + grid.scrollSize
            }
            if grid.getPaint().getTouchMoveView() == grid && (grid.hoverScrollVButton || grid.downScrollVButton) {
                paint.fillRect(color:grid.scrollBarHoveredColor, left:grid.size.cx - grid.scrollSize, top:sTop, right:grid.size.cx, bottom:sBottom)
            } else {
                paint.fillRect(color:grid.scrollBarColor, left:grid.size.cx - grid.scrollSize, top:sTop, right:grid.size.cx, bottom:sBottom)
            }
            grid.vScrollIsVisible = true
        }
    }
}

/*
* 获取内容的宽度
* grid:表格
*/
func getGridContentWidth(grid:FCGrid)->Double {
    var cWidth:Double = 0
    if grid.columns.count > 0{
        for i in 0...grid.columns.count - 1{
            if grid.columns[i].visible {
                cWidth += grid.columns[i].width
            }
        }
    }
    return cWidth
}

/*
* 获取内容的高度
* grid:表格
*/
func getGridContentHeight(grid:FCGrid)->Double {
    var cHeight:Double = 0
    if grid.rows.count > 0{
        for i in 0...grid.rows.count - 1 {
            if grid.rows[i].visible {
                cHeight += grid.rowHeight
            }
        }
    }
    return cHeight
}

/*
* 表格的鼠标移动方法
* grid: 表格
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
*/
func touchMoveGrid(grid:FCGrid, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint) {
    grid.hoverScrollHButton = false
    grid.hoverScrollVButton = false
    let mp = FCPoint(x:firstPoint.x, y:firstPoint.y)
    let paint = grid.getPaint()
    if firstTouch {
        if paint.resizeColumnState != 0 {
            let gridColumn = grid.columns[paint.resizeColumnIndex]
            let newWidth = paint.resizeColumnBeginWidth + (mp.x - grid.startPoint.x)
            if newWidth > 10 {
                gridColumn.width = newWidth
            }
            return
        }
        if grid.showHScrollBar || grid.showVScrollBar {
            if grid.downScrollHButton {
                let contentWidth = getGridContentWidth(grid:grid)
                let subX = (mp.x - grid.startPoint.x) / grid.size.cx * contentWidth
                var newScrollH = grid.startScrollH + subX
                if newScrollH < 0 {
                    newScrollH = 0
                } else if newScrollH > contentWidth - grid.size.cx {
                    newScrollH = contentWidth - grid.size.cx
                }
                grid.scrollH = newScrollH
                paint.cancelClick = true
                return

            } else if grid.downScrollVButton {
                let contentHeight = getGridContentHeight(grid:grid)
                let subY = (mp.y - grid.startPoint.y) / (grid.size.cy - grid.headerHeight - grid.scrollSize) * contentHeight
                var newScrollV = grid.startScrollV + subY
                if newScrollV < 0 {
                    newScrollV = 0
                } else if newScrollV > contentHeight - (grid.size.cy - grid.headerHeight - grid.scrollSize) {
                    newScrollV = contentHeight - (grid.size.cy - grid.headerHeight - grid.scrollSize)
                }
                grid.scrollV = newScrollV
                paint.cancelClick = true
                return
            }
        }
        if grid.allowDragScroll {
            let contentWidth = getGridContentWidth(grid:grid)
            if contentWidth > grid.size.cx - grid.scrollSize {
                let subX = grid.startPoint.x - mp.x
                var newScrollH = grid.startScrollH + subX
                if newScrollH < 0 {
                    newScrollH = 0
                } else if newScrollH > contentWidth - grid.size.cx {
                    newScrollH = contentWidth - grid.size.cx
                }
                grid.scrollH = newScrollH
                if subX > 5 || subX < -5 {
                    paint.cancelClick = true
                }
            }
            let contentHeight = getGridContentHeight(grid:grid)
            if contentHeight > grid.size.cy - grid.headerHeight - grid.scrollSize {
                let subY = grid.startPoint.y - mp.y
                var newScrollV = grid.startScrollV + subY
                if newScrollV < 0 {
                    newScrollV = 0
                } else if newScrollV > contentHeight - (grid.size.cy - grid.headerHeight - grid.scrollSize) {
                    newScrollV = contentHeight - (grid.size.cy - grid.headerHeight - grid.scrollSize)
                }
                grid.scrollV = newScrollV
                if subY > 5 || subY < -5 {
                    paint.cancelClick = true
                }
            }
        }
    } else {
        if grid.showHScrollBar {
            let contentWidth = getGridContentWidth(grid:grid)
            if contentWidth > 0 && contentWidth > grid.size.cx - grid.scrollSize {
                let sLeft = grid.scrollH / contentWidth * grid.size.cx
                var sRight = (grid.scrollH + grid.size.cx) / contentWidth * grid.size.cx
                if sRight - sLeft < grid.scrollSize {
                    sRight = sLeft + grid.scrollSize
                }
                if mp.x >= sLeft && mp.x <= sRight && mp.y >= grid.size.cy - grid.scrollSize && mp.y <= grid.size.cy {
                    grid.hoverScrollHButton = true
                    return
                } else {
                    grid.hoverScrollHButton = false
                }
            }
        }
        if grid.showVScrollBar {
            let contentHeight = getGridContentHeight(grid:grid)
            if contentHeight > 0 && contentHeight > grid.size.cy - grid.headerHeight - grid.scrollSize {
                let sTop = grid.headerHeight + grid.scrollV / contentHeight * (grid.size.cy - grid.headerHeight - grid.scrollSize)
                var sBottom = grid.headerHeight + (grid.scrollV + (grid.size.cy - grid.headerHeight - grid.scrollSize)) / contentHeight * (grid.size.cy - grid.headerHeight - grid.scrollSize)
                if sBottom - sTop < grid.scrollSize {
                    sBottom = sTop + grid.scrollSize
                }
                if mp.x >= grid.size.cx - grid.scrollSize && mp.x <= grid.size.cx && mp.y >= sTop && mp.y <= sBottom {
                    grid.hoverScrollVButton = true
                    return
                } else {
                    grid.hoverScrollVButton = false
                }
            }
        }
    }
}

/*
* 表格的鼠标按下方法
* grid: 表格
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
* clicks:点击次数
*/
func touchDownGrid(grid:FCGrid, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint, clicks:Int) {
    let mp = FCPoint(x:firstPoint.x, y:firstPoint.y)
    grid.startPoint = mp
    grid.touchDownTime = getTickCount()
    grid.downScrollHButton = false
    grid.downScrollVButton = false
    grid.hoverScrollHButton = false
    grid.hoverScrollVButton = false
    grid.scrollAddSpeed = 0
    grid.isScrolling = false
    if grid.showHScrollBar {
        let contentWidth = getGridContentWidth(grid:grid)
        if contentWidth > 0 && contentWidth > grid.size.cx - grid.scrollSize {
            let sLeft = grid.scrollH / contentWidth * grid.size.cx
            var sRight = (grid.scrollH + grid.size.cx) / contentWidth * grid.size.cx
            if sRight - sLeft < grid.scrollSize {
                sRight = sLeft + grid.scrollSize
            }
            if mp.x >= sLeft && mp.x <= sRight && mp.y >= grid.size.cy - grid.scrollSize && mp.y <= grid.size.cy{
                grid.downScrollHButton = true
                grid.startScrollH = grid.scrollH
                return
            }
        }
    }
    if grid.showVScrollBar {
        let contentHeight = getGridContentHeight(grid:grid)
        if contentHeight > 0 && contentHeight > grid.size.cy - grid.headerHeight - grid.scrollSize {
            let sTop = grid.headerHeight + grid.scrollV / contentHeight * (grid.size.cy - grid.headerHeight - grid.scrollSize)
            var sBottom = grid.headerHeight + (grid.scrollV + (grid.size.cy - grid.headerHeight - grid.scrollSize)) / contentHeight * (grid.size.cy - grid.headerHeight - grid.scrollSize)
            if sBottom - sTop < grid.scrollSize {
                sBottom = sTop + grid.scrollSize
            }
            if mp.x >= grid.size.cx - grid.scrollSize && mp.x <= grid.size.cx && mp.y >= sTop && mp.y <= sBottom {
                grid.downScrollVButton = true
                grid.startScrollV = grid.scrollV
                return
            }
        }
    }
    if grid.allowDragScroll {
        grid.startScrollH = grid.scrollH
        grid.startScrollV = grid.scrollV
    }
    var colLeft = 0.0
    if grid.columns.count > 0{
        for i in 0...grid.columns.count - 1{
            let colRect = FCRect(left:colLeft, top:0, right:colLeft + grid.columns[i].width, bottom:grid.headerHeight)
            grid.columns[i].bounds = colRect
            grid.columns[i].index = i
            colLeft += grid.columns[i].width
        }
    }
    let paint = grid.getPaint()
    paint.resizeColumnState = 0
    paint.resizeColumnBeginWidth = 0
    if grid.headerHeight > 0 && mp.y <= grid.headerHeight && grid.columns.count > 0 {
        //绘制列
        for i in 0...grid.columns.count - 1{
            let gridColumn = grid.columns[i]
            if gridColumn.visible {
                let bounds = gridColumn.bounds
                if mp.x >= bounds.left - grid.scrollH && mp.x <= bounds.right - grid.scrollH {
                    if gridColumn.index > 0 && mp.x < bounds.left + 5 - grid.scrollH  {
                        paint.resizeColumnState = 1
                        paint.resizeColumnBeginWidth = grid.columns[gridColumn.index - 1].bounds.right - grid.columns[gridColumn.index - 1].bounds.left
                        paint.resizeColumnIndex = gridColumn.index - 1
                        return
                    }
                    else if mp.x > bounds.right - 5 - grid.scrollH {
                        paint.resizeColumnState = 2
                        paint.resizeColumnBeginWidth = bounds.right - bounds.left
                        paint.resizeColumnIndex = gridColumn.index
                        return
                    }
                    break
                }
            }
        }
    }
}

/*
 * 表格行升序
 */
func sortGridRowAsc(x:FCGridRow, y:FCGridRow)->Bool{
    let leftCell = x.cells[x.sortColIndex]
    let rightCell = y.cells[y.sortColIndex]
    let leftColumn = leftCell.getColumn()
    if leftColumn.colType == "double"{
        let leftValue = Double(leftCell.value)!
        let rightValue = Double(rightCell.value)!
        if rightValue > leftValue{
            return true;
        }else{
            return false;
        }
    }else if leftColumn.colType == "int"{
        let leftValue = Int(leftCell.value)!
        let rightValue = Int(rightCell.value)!
        if rightValue > leftValue{
            return true;
        }else{
            return false;
        }
    }else if leftColumn.colType == "bool"{
        var leftValue = 1
        var rightValue = 1
        if leftCell.value == "false"{
            leftValue = 0
        }
        if rightCell.value == "false"{
            rightValue =  0
        }
        if rightValue > leftValue{
            return true;
        }else{
            return false;
        }
    }else{
        if rightCell.value > leftCell.value{
            return true;
        }else{
            return false;
        }
    }
}

/*
 * 表格行降序
 */
func sortGridRowDesc(x:FCGridRow, y:FCGridRow)->Bool{
    let leftCell = x.cells[x.sortColIndex]
    let rightCell = y.cells[y.sortColIndex]
    let leftColumn = leftCell.getColumn()
    if leftColumn.colType == "double"{
        let leftValue = Double(leftCell.value)!
        let rightValue = Double(rightCell.value)!
        if rightValue < leftValue{
            return true;
        }else{
            return false;
        }
    }else if leftColumn.colType == "int"{
        let leftValue = Int(leftCell.value)!
        let rightValue = Int(rightCell.value)!
        if rightValue < leftValue{
            return true;
        }else{
            return false;
        }
    }else if leftColumn.colType == "bool"{
        var leftValue = 1
        var rightValue = 1
        if leftCell.value == "false"{
            leftValue = 0
        }
        if rightCell.value == "false"{
            rightValue =  0
        }
        if rightValue < leftValue{
            return true;
        }else{
            return false;
        }
    }else{
        if rightCell.value < leftCell.value{
            return true;
        }else{
            return false;
        }
    }
}

/*
* 表格的鼠标抬起方法
* grid: 表格
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
* clicks:点击次数
*/
func touchUpGrid(grid:FCGrid, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint, clicks:Int) {
    grid.hoverScrollHButton = false
    grid.hoverScrollVButton = false
    if grid.getPaint().cancelClick{
        return
    }
    if firstTouch {
        if grid.allowDragScroll {
            let touchUpTime = getTickCount()
            let diff = Double(touchUpTime - grid.touchDownTime)
            //加速滚动
            if diff > 0 && diff < 250 {
                let sub1 = Int(30 * ((abs(firstPoint.y - grid.startPoint.y)) / 20) / diff * 10)
                let sub2 = Int(30 * ((abs(firstPoint.x - grid.startPoint.x)) / 20) / diff * 10)
                if abs(sub1) > abs(sub2) {
                    if firstPoint.y < grid.startPoint.y {
                        grid.scrollAddSpeed += sub1
                    } else {
                        grid.scrollAddSpeed -= sub1
                    }
                    grid.scrollDirection = 0
                } else {
                    if firstPoint.x < grid.startPoint.x {
                        grid.scrollAddSpeed += sub2
                    } else {
                        grid.scrollAddSpeed -= sub2
                    }
                    grid.scrollDirection = 1
                }
                grid.isScrolling = true
                if abs(grid.scrollAddSpeed) > 0 {
                    grid.getPaint().cancelClick = true
                }
            }
        }
    }
    grid.downScrollHButton = false
    grid.downScrollVButton = false
    var cTop = -grid.scrollV + grid.headerHeight
    //绘制行
    var colLeft = 0.0
    if grid.columns.count > 0{
        for i in 0...grid.columns.count - 1{
            let colRect = FCRect(left:colLeft, top:0, right:colLeft + grid.columns[i].width, bottom:grid.headerHeight)
            grid.columns[i].bounds = colRect
            grid.columns[i].index = i
            colLeft += grid.columns[i].width
        }
    }
    if grid.headerHeight > 0 && firstPoint.y <= grid.headerHeight && grid.columns.count > 0{
        var cLeft = 0.0
        //绘制列
        for i in 0...grid.columns.count - 1{
            let gridColumn = grid.columns[i]
            if grid.columns[i].visible {
                if gridColumn.frozen {
                    if firstPoint.x >= cLeft && firstPoint.x <= cLeft + gridColumn.width {
                        for j in 0...grid.columns.count - 1{
                            let tColumn = grid.columns[j]
                            if tColumn == gridColumn {
                                if tColumn.allowSort {
                                    if tColumn.sort == "none" || tColumn.sort == "desc" {
                                        tColumn.sort = "asc"
                                        if grid.rows.count > 0{
                                            for r in 0...grid.rows.count - 1{
                                                grid.rows[r].sortColIndex = j
                                            }
                                            grid.rows.sort(by: sortGridRowAsc)
                                        }
                                    } else {
                                        tColumn.sort = "desc"
                                        if grid.rows.count > 0{
                                            for r in 0...grid.rows.count - 1{
                                                grid.rows[r].sortColIndex = j
                                            }
                                            grid.rows.sort(by: sortGridRowDesc)
                                        }
                                    }
                                } else {
                                    tColumn.sort = "none"
                                }
                            } else {
                                tColumn.sort = "none"
                            }
                        }
                        if grid.hasClickGridColumnEvent{
                            grid.onClickGridColumn(grid, gridColumn, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
                        }
                        else if grid.getPaint().hasClickGridColumnEvent{
                            grid.getPaint().onClickGridColumn(grid, gridColumn, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
                        }
                        return
                    }
                }
                cLeft += gridColumn.width
            }
        }
        cLeft = -grid.scrollH
        for i in 0...grid.columns.count - 1{
            let gridColumn = grid.columns[i]
            if grid.columns[i].visible {
                if !gridColumn.frozen {
                    if firstPoint.x >= cLeft && firstPoint.x <= cLeft + gridColumn.width {
                        for j in 0...grid.columns.count - 1{
                            let tColumn = grid.columns[j]
                            if tColumn == gridColumn{
                                if tColumn.allowSort {
                                    if tColumn.sort == "none" || tColumn.sort == "desc" {
                                        tColumn.sort = "asc"
                                        if grid.rows.count > 0{
                                            for r in 0...grid.rows.count - 1{
                                                grid.rows[r].sortColIndex = j
                                            }
                                            grid.rows.sort(by: sortGridRowAsc)
                                        }
                                    } else {
                                        tColumn.sort = "desc"
                                        if grid.rows.count > 0{
                                            for r in 0...grid.rows.count - 1{
                                                grid.rows[r].sortColIndex = j
                                            }
                                            grid.rows.sort(by: sortGridRowDesc)
                                        }
                                    }
                                } else {
                                    tColumn.sort = "none"
                                }
                            } else {
                                tColumn.sort = "none"
                            }
                        }
                        if grid.hasClickGridColumnEvent{
                            grid.onClickGridColumn(grid, gridColumn, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
                        }
                        else if grid.getPaint().hasClickGridColumnEvent{
                            grid.getPaint().onClickGridColumn(grid, gridColumn, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
                        }
                        return
                    }
                }
                cLeft += gridColumn.width
            }
        }
    }
    if grid.rows.count > 0{
        for i in 0...grid.rows.count - 1{
            let row = grid.rows[i]
            if row.visible {
                let rTop = cTop, rBottom = cTop + grid.rowHeight
                if rBottom >= 0 && cTop <= grid.size.cy {
                    for j in 0...row.cells.count - 1{
                        let cell = row.cells[j]
                        var gridColumn = cell.getColumn()
                        if !gridColumn.isNotEmpty {
                            gridColumn = grid.columns[j]
                        }
                        if gridColumn.visible {
                            if gridColumn.frozen {
                                var cellWidth = gridColumn.width
                                let colSpan = cell.colSpan
                                if colSpan > 1 {
                                    for n in 1...colSpan - 1{
                                        let spanColumn = grid.columns[gridColumn.index + n]
                                        if spanColumn.isNotEmpty && spanColumn.visible {
                                            cellWidth += spanColumn.width
                                        }
                                    }
                                }
                                var cellHeight = grid.rowHeight
                                let rowSpan = cell.rowSpan
                                if rowSpan > 1 {
                                    for n in 0...rowSpan - 1{
                                        let spanRow = grid.rows[i + n]
                                        if spanRow.isNotEmpty && spanRow.visible{
                                            cellHeight += grid.rowHeight
                                        }
                                    }
                                }

                                let cRect = FCRect(left:gridColumn.bounds.left, top:rTop, right:gridColumn.bounds.left + cellWidth, bottom:rTop + cellHeight)
                                if cRect.right >= 0 && cRect.left < grid.size.cx {
                                    if (firstPoint.x >= cRect.left && firstPoint.x <= cRect.right && firstPoint.y >= cRect.top && firstPoint.y <= cRect.bottom) {
                                        for r in 0...grid.rows.count - 1{
                                            let subRow = grid.rows[r]
                                            if subRow == row {
                                                subRow.selected = true
                                            } else {
                                                subRow.selected = false
                                            }
                                        }
                                        if grid.hasClickGridCellEvent{
                                            grid.onClickGridCell(grid, row, gridColumn, cell, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
                                        }
                                        else if grid.getPaint().hasClickGridCellEvent{
                                            grid.getPaint().onClickGridCell(grid, row, gridColumn, cell, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
                                        }
                                        return
                                    }
                                }
                            }
                        }
                    }
                }
                if rBottom >= 0 && cTop <= grid.size.cy {
                    for j in 0...row.cells.count - 1{
                        let cell = row.cells[j]
                        var gridColumn = cell.getColumn()
                        if !gridColumn.isNotEmpty {
                            gridColumn = grid.columns[j]
                        }
                        if gridColumn.visible {
                            if !gridColumn.frozen {
                                var cellWidth = gridColumn.width
                                let colSpan = cell.colSpan
                                if colSpan > 1 {
                                    for n in 1...colSpan - 1{
                                        let spanColumn = grid.columns[gridColumn.index + n]
                                        if spanColumn.isNotEmpty && spanColumn.visible {
                                            cellWidth += spanColumn.width
                                        }
                                    }
                                }
                                var cellHeight = grid.rowHeight
                                let rowSpan = cell.rowSpan
                                if rowSpan > 1 {
                                    for n in 0...rowSpan - 1{
                                        let spanRow = grid.rows[i + n]
                                        if spanRow.isNotEmpty && spanRow.visible {
                                            cellHeight += grid.rowHeight
                                        }
                                    }
                                }

                                let cRect = FCRect(left:gridColumn.bounds.left - grid.scrollH, top:rTop, right:gridColumn.bounds.left + cellWidth - grid.scrollH, bottom:rTop + cellHeight)
                                if cRect.right >= 0 && cRect.left < grid.size.cx {
                                    if firstPoint.x >= cRect.left && firstPoint.x <= cRect.right && firstPoint.y >= cRect.top && firstPoint.y <= cRect.bottom {
                                        for r in 0...grid.rows.count - 1{
                                            let subRow = grid.rows[r]
                                            if subRow == row {
                                                subRow.selected = true
                                            } else {
                                                subRow.selected = false
                                            }
                                        }
                                        if grid.hasClickGridCellEvent{
                                            grid.onClickGridCell(grid, row, gridColumn, cell, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
                                        }
                                        else if grid.getPaint().hasClickGridCellEvent{
                                            grid.getPaint().onClickGridCell(grid, row, gridColumn, cell, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
                                        }
                                        return
                                    }
                                }
                            }
                        }
                    }
                }
                if cTop > grid.size.cy {
                    break
                }
                cTop += grid.rowHeight
            }
        }
    }
}

/*
* 表格的鼠标滚轮方法
* grid:表格
* delta:滚轮值
*/
func touchWheelGrid(grid:FCGrid, delta:Int) {
    var oldScrollV = grid.scrollV
    if delta > 0 {
        oldScrollV -= grid.rowHeight
    } else if delta < 0 {
        oldScrollV += grid.rowHeight
    }
    let contentHeight = getGridContentHeight(grid:grid)
    if contentHeight < grid.size.cy - grid.headerHeight - grid.scrollSize{
        grid.scrollV = 0
    } else {
        if oldScrollV < 0 {
            oldScrollV = 0
        } else if oldScrollV > contentHeight - grid.size.cy + grid.headerHeight + grid.scrollSize {
            oldScrollV = contentHeight - grid.size.cy + grid.headerHeight + grid.scrollSize
        }
        grid.scrollV = oldScrollV
    }
}

/*
 * 检查表格滚动
 * grid:表格
 */
func checkGridScroll(grid:FCGrid){
    if grid.isScrolling {
        var sub = Int(grid.scrollAddSpeed / 10)
        if sub == 0 && grid.scrollAddSpeed > 1 {
            sub = 1
        } else if sub == 0 && grid.scrollAddSpeed < -1 {
            sub = -1
        }
        grid.scrollAddSpeed -= sub
        if abs(sub) <= 1 {
            grid.isScrolling = false
            grid.scrollAddSpeed = 0
            invalidateView(view:grid)
        } else {
            var oldScrollV = grid.scrollV + Double(grid.scrollAddSpeed)
            var oldScrollH = grid.scrollH + Double(grid.scrollAddSpeed)
            if grid.scrollDirection == 0 {
                let contentHeight = getGridContentHeight(grid:grid)
                if contentHeight < grid.size.cy - grid.scrollSize{
                    grid.scrollV = 0
                } else {
                    if oldScrollV < 0 {
                        oldScrollV = 0
                    } else if oldScrollV > contentHeight - grid.size.cy + grid.headerHeight + grid.scrollSize {
                        oldScrollV = contentHeight - grid.size.cy + grid.headerHeight + grid.scrollSize
                    }
                    grid.scrollV = oldScrollV
                }
            } else {
                let contentWidth = getGridContentWidth(grid:grid)
                if contentWidth < grid.size.cx - grid.headerHeight - grid.scrollSize {
                    grid.scrollH = 0
                } else {
                    if oldScrollH < 0 {
                        oldScrollH = 0
                    } else if oldScrollH > contentWidth - grid.size.cx {
                        oldScrollH = contentWidth - grid.size.cx
                    }
                    grid.scrollH = oldScrollH
                }
            }
            invalidateView(view:grid)
        }
    }
}

/*
* 重置布局图层
* layout:布局层
*/
func resetLayoutDiv(layout:FCLayoutDiv) {
    //var reset = false
    var padding = FCPadding(left:0, top:0, right:0, bottom:0)
    if layout.padding.isNotEmpty {
        padding = layout.padding
    }
    var vPos = 0
    var left = padding.left, top = padding.top, width = layout.size.cx - padding.left - padding.right, height = layout.size.cy - padding.top - padding.bottom
    if layout.views.count > 0{
        for i in 0...layout.views.count - 1{
            let view = layout.views[i]
            if view.visible {
                let size = view.size
                var margin = FCPadding(left:0, top:0, right:0, bottom:0)
                if view.margin.isNotEmpty{
                    margin = view.margin
                }
                let cLeft = view.location.x, cTop = view.location.y, cWidth = size.cx, cHeight = size.cy
                var nLeft = cLeft, nTop = cTop, nWidth = cWidth, nHeight = cHeight
                if layout.layoutStyle == "bottomtotop" {
                    if i == 0 {
                        top = height - padding.top
                    }
                    var lWidth:Double = 0
                    if layout.autoWrap {
                        lWidth = size.cx
                        let lTop = top - margin.top - cHeight - margin.bottom
                        if lTop < padding.top {
                            if vPos != 0 {
                                left += cWidth + margin.left
                            }
                            top = height - padding.top
                        }
                    }
                    else {
                        lWidth = width - margin.left - margin.right
                    }
                    top -= cHeight + margin.bottom
                    nLeft = left + margin.left
                    nWidth = lWidth
                    nTop = top
                } else if layout.layoutStyle == "lefttoright" {
                    var lHeight:Double = 0
                    if layout.autoWrap {
                        lHeight = size.cy
                        let lRight = left + margin.left + cWidth + margin.right
                        if lRight > width {
                            left = padding.left
                            if vPos != 0 {
                                top += cHeight + margin.top
                            }
                        }
                    }
                    else {
                        lHeight = height - margin.top - margin.bottom
                    }
                    left += margin.left
                    nLeft = left
                    nTop = top + margin.top
                    nHeight = lHeight
                    left += cWidth + margin.right
                } else if layout.layoutStyle == "righttoleft" {
                    if i == 0 {
                        left = width - padding.left
                    }
                    var lHeight:Double = 0
                    if layout.autoWrap {
                        lHeight = size.cy
                        let lLeft = left - margin.left - cWidth - margin.right
                        if lLeft < padding.left {
                            left = width - padding.left
                            if vPos != 0 {
                                top += cHeight + margin.top
                            }
                        }
                    }
                    else {
                        lHeight = height - margin.top - margin.bottom
                    }
                    left -= cWidth + margin.left
                    nLeft = left
                    nTop = top + margin.top
                    nHeight = lHeight
                } else if layout.layoutStyle == "toptobottom" {
                    var lWidth:Double = 0
                    if layout.autoWrap {
                        lWidth = size.cx
                        let lBottom = top + margin.top + cHeight + margin.bottom
                        if lBottom > height {
                            if (vPos != 0) {
                                left += cWidth + margin.left + margin.right
                            }
                            top = padding.top
                        }
                    }
                    else {
                        lWidth = width - margin.left - margin.right
                    }
                    top += margin.top
                    nTop = top
                    nLeft = left + margin.left
                    nWidth = lWidth
                    top += cHeight + margin.bottom
                }
                if cLeft != nLeft || cTop != nTop || cWidth != nWidth || cHeight != nHeight {
                    view.location = FCPoint(x:nLeft, y:nTop)
                    view.size = FCSize(cx:nWidth, cy:nHeight)
                    //reset = true
                }
                vPos += 1
            }
        }
    }
    //return reset
}

/*
* 更新页的布局
* tabView:多页夹
* tabPage:页
* left:左侧坐标
* top:上方坐标
* width:宽度
* height:高度
* tw:页头按钮的宽度
* th:页头按钮的高度
*/
func updataPageLayout(tabView:FCTabView, tabPage:FCTabPage, left:Double, top:Double, width:Double, height:Double, tw:Double, th:Double) {
    let newBounds = FCRect(left:0, top:0, right:0, bottom:0)
    if tabView.layout == "bottom" {
        newBounds.left = 0
        newBounds.top = 0
        newBounds.right = width
        newBounds.bottom = height - th
        tabPage.getHeaderButton().location = FCPoint(x:left, y:height - th)
    } else if tabView.layout == "left" {
        newBounds.left = tw
        newBounds.top = 0
        newBounds.right = width
        newBounds.bottom = height
        tabPage.getHeaderButton().location = FCPoint(x:0, y:top)
    } else if tabView.layout == "right" {
        newBounds.left = 0
        newBounds.top = 0
        newBounds.right = width - tw
        newBounds.bottom = height
        tabPage.getHeaderButton().location = FCPoint(x:width - tw, y:top)
    } else if tabView.layout == "top" {
        newBounds.left = 0
        newBounds.top = th
        newBounds.right = width
        newBounds.bottom = height
        tabPage.getHeaderButton().location = FCPoint(x:left, y:0)
    }
    tabPage.location = FCPoint(x:newBounds.left, y:newBounds.top)
    tabPage.size = FCSize(cx:newBounds.right - newBounds.left, cy:newBounds.bottom - newBounds.top)
}

/*
* 更新多页夹的布局
* tabView:多页夹
*/
func updateTabLayout(tabView:FCTabView) {
    let width = tabView.size.cx
    let height = tabView.size.cy
    var left:Double = 0
    var top:Double = 0
    if tabView.tabPages.count > 0{
        for i in 0...tabView.tabPages.count - 1{
            let tabPage = tabView.tabPages[i]
            let headerButton = tabView.tabPages[i].getHeaderButton()
            if headerButton.visible {
                let tw = headerButton.size.cx
                let th = headerButton.size.cy
                updataPageLayout(tabView:tabView, tabPage:tabPage, left:left, top:top, width:width, height:height, tw:tw, th:th)
                left += tw
                top += th
            } else {
                tabPage.visible = false
            }
        }
    }
}

/*
* 重置分割线的布局
* split:分割视图
*/
func resetSplitLayoutDiv(split:FCSplitLayoutDiv){
    //var reset = false
    let splitRect = FCRect(left:0, top:0, right:0, bottom:0)
    let width = split.size.cx, height = split.size.cy
    let fRect = FCRect(left:0, top:0, right:0, bottom:0)
    let sRect = FCRect(left:0, top:0, right:0, bottom:0)
    let splitter = split.getSplitter()
    let splitterSize = FCSize(cx:0, cy:0)
    if splitter.visible {
        splitterSize.cx = splitter.size.cx
        splitterSize.cy = splitter.size.cy
    }
    let layoutStyle = split.layoutStyle
    if layoutStyle == "bottomtotop" {
        if split.splitMode == "absolutesize" || split.oldSize.cy == 0 {
            splitRect.left = 0
            splitRect.top = height - (split.oldSize.cy - splitter.location.y)
            splitRect.right = width
            splitRect.bottom = splitRect.top + splitterSize.cy
        }
        else if split.splitMode == "percentsize" {
            splitRect.left = 0
            if split.splitPercent == -1 {
                split.splitPercent = splitter.location.y / split.oldSize.cy
            }
            splitRect.top = height * split.splitPercent
            splitRect.right = width
            splitRect.bottom = splitRect.top + splitterSize.cy
        }
        fRect.left = 0
        fRect.top = splitRect.bottom
        fRect.right = width
        fRect.bottom = height
        sRect.left = 0
        sRect.top = 0
        sRect.right = width
        sRect.bottom = splitRect.top
    }
    else if layoutStyle == "lefttoright" {
        if split.splitMode == "absolutesize" || split.oldSize.cx == 0 {
            splitRect.left = splitter.location.x
            splitRect.top = 0
            splitRect.right = splitRect.left + splitterSize.cx
            splitRect.bottom = height
        }
        else if split.splitMode == "percentsize" {
            if split.splitPercent == -1 {
                split.splitPercent = splitter.location.x / split.oldSize.cx
            }
            splitRect.left = width * split.splitPercent
            splitRect.top = 0
            splitRect.right = splitRect.left + splitterSize.cx
            splitRect.bottom = height
        }
        fRect.left = 0
        fRect.top = 0
        fRect.right = splitRect.left
        fRect.bottom = height
        sRect.left = splitRect.right
        sRect.top = 0
        sRect.right = width
        sRect.bottom = height
    }
    else if layoutStyle == "righttoleft" {
        if split.splitMode == "absolutesize" || split.oldSize.cx == 0 {
            splitRect.left = width - (split.oldSize.cx - splitter.location.x)
            splitRect.top = 0
            splitRect.right = splitRect.left + splitterSize.cx
            splitRect.bottom = height
        }
        else if split.splitMode == "percentsize" {
            if split.splitPercent == -1 {
                split.splitPercent = splitter.location.x / split.oldSize.cx
            }
            splitRect.left = width * split.splitPercent
            splitRect.top = 0
            splitRect.right = splitRect.left + splitterSize.cx
            splitRect.bottom = height
        }
        fRect.left = splitRect.right
        fRect.top = 0
        fRect.right = width
        fRect.bottom = height
        sRect.left = 0
        sRect.top = 0
        sRect.right = splitRect.left
        sRect.bottom = height
    }
    else if layoutStyle == "toptobottom" {
        if split.splitMode == "absolutesize" || split.oldSize.cy == 0 {
            splitRect.left = 0
            splitRect.top = splitter.location.y
            splitRect.right = width
            splitRect.bottom = splitRect.top + splitterSize.cy
        }
        else if split.splitMode == "percentsize"{
            splitRect.left = 0
            if split.splitPercent == -1 {
                split.splitPercent = splitter.location.y / split.oldSize.cy
            }
            splitRect.top = height * split.splitPercent
            splitRect.right = width
            splitRect.bottom = splitRect.top + splitterSize.cy
        }
        fRect.left = 0
        fRect.top = 0
        fRect.right = width
        fRect.bottom = splitRect.top
        sRect.left = 0
        sRect.top = splitRect.bottom
        sRect.right = width
        sRect.bottom = height
    }
    if splitter.visible {
        let spRect = FCRect(left:splitter.location.x, top:splitter.location.y, right:splitter.location.x + splitter.size.cx, bottom:splitter.location.y + splitter.size.cy)
        if spRect.left != splitRect.left || spRect.top != splitRect.top || spRect.right != splitRect.right || spRect.bottom != splitRect.bottom {
            splitter.location = FCPoint(x:splitRect.left, y:splitRect.top)
            splitter.size = FCSize(cx:splitRect.right - splitRect.left, cy:splitRect.bottom - splitRect.top)
            //reset = true
        }
    }
    let firstView = split.getFirstView()
    let fcRect = FCRect(left:firstView.location.x, top:firstView.location.y, right:firstView.location.x + firstView.size.cx, bottom:firstView.location.y + firstView.size.cy)
    if fcRect.left != fRect.left || fcRect.top != fRect.top || fcRect.right != fRect.right || fcRect.bottom != fRect.bottom {
        //reset = true
        firstView.location = FCPoint(x:fRect.left, y:fRect.top)
        firstView.size = FCSize(cx:fRect.right - fRect.left, cy:fRect.bottom - fRect.top)
    }
    let secondView = split.getSecondView()
    let scRect = FCRect(left:secondView.location.x, top:secondView.location.y, right:secondView.location.x + secondView.size.cx, bottom:secondView.location.y + secondView.size.cy)
    if scRect.left != sRect.left || scRect.top != sRect.top || scRect.right != sRect.right || scRect.bottom != sRect.bottom {
        //reset = true
        secondView.location = FCPoint(x:sRect.left, y:sRect.top)
        secondView.size = FCSize(cx:sRect.right - sRect.left, cy:sRect.bottom - sRect.top)
    }
    split.oldSize = FCSize(cx:width, cy:height)
    //return reset
}


/*
* 添加页
* tabView:多页夹
* tabPage:页
* tabButton:页头按钮
*/
func addTabPage(tabView:FCTabView, tabPage:FCTabPage, tabButton:FCView) {
    tabPage.setHeaderButton(view: tabButton)
    tabPage.setParent(parent:tabView)
    tabPage.setPaint(paint:tabView.getPaint())
    tabButton.setParent(parent:tabView)
    tabButton.setPaint(paint:tabView.getPaint())
    tabView.tabPages.append(tabPage)
    tabView.views.append(tabPage)
    tabView.views.append(tabButton)
}

/*
* 移除页
* tabView:多页夹
* tabPage:页
*/
func removeTabPage(tabView:FCTabView, pageOrButton:FCView) {
    if tabView.tabPages.count > 0{
        for i in 0...tabView.tabPages.count - 1 {
            let tabPage = tabView.tabPages[i]
            if(tabPage.getHeaderButton() == pageOrButton || tabPage == pageOrButton){
                tabView.tabPages.remove(at:i)
                removeViewFromParent(view:tabPage.getHeaderButton(), parent:tabView)
                removeViewFromParent(view:tabPage, parent:tabView)
                break
            }
        }
    }
    if(tabView.tabPages.count > 0){
        selectTabPage(tabView:tabView, tabPage:tabView.tabPages[0])
    }
    updateTabLayout(tabView:tabView)
}

/*
* 选中页
* tabView:多页夹
* tabPage:页
*/
func selectTabPage(tabView:FCTabView, tabPage:FCTabPage) {
    if tabView.views.count > 0{
        for i in 0...tabView.tabPages.count - 1 {
            let tp = tabView.tabPages[i]
            if tp == tabPage {
                tp.visible = true
            } else {
                tp.visible = false
            }
        }
    }
    updateTabLayout(tabView:tabView)
}

/*
* 重绘多页加
* tabView:多页夹
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawTabViewBorder(tabView:FCTabView, paint:FCPaint, clipRect:FCRect) {
    if tabView.underLineColor != "none" {
        if tabView.views.count > 0{
            for i in 0...tabView.tabPages.count - 1 {
                let tp = tabView.tabPages[i]
                if tp.visible {
                    let headerButton = tp.getHeaderButton()
                    let location = FCPoint(x:headerButton.location.x, y:headerButton.location.y)
                    let size = headerButton.size
                    if tabView.useAnimation {
                        if tabView.underPoint.x != 0 && tabView.underPoint.y != 0 {
                            location.x = tabView.underPoint.x
                            location.y = tabView.underPoint.y
                        }
                    }
                    if tabView.layout == "bottom" {
                        paint.fillRect(color:tabView.underLineColor, left:location.x, top:location.y, right:location.x + size.cx, bottom:location.y + tabView.underLineSize)
                    } else if tabView.layout == "left" {
                        paint.fillRect(color:tabView.underLineColor, left:location.x + size.cx - tabView.underLineSize, top:location.y, right:location.x + size.cx, bottom:location.y + size.cy)
                    } else if tabView.layout == "top" {
                        paint.fillRect(color:tabView.underLineColor, left:location.x, top:location.y + size.cy - tabView.underLineSize, right:location.x + size.cx, bottom:location.y + size.cy)
                    }
                    else if tabView.layout == "right" {
                        paint.fillRect(color:tabView.underLineColor, left:location.x, top:location.y, right:location.x + tabView.underLineSize, bottom:location.y + size.cy)
                    }
                    break
                }
            }
        }
    }
}

/*
* 获取总的偏移量
* node:树节点
*/
func getTotalIndent(node:FCTreeNode)->Double {
    if node.getParentNode().isNotEmpty {
        return node.indent + getTotalIndent(node:node.getParentNode())
    } else {
        return node.indent
    }
}

/*
* 绘制单元格
* tree:树
* row:行
* column:列
* node:节点
* paint:绘图对象
* left:左侧坐标
* top:上方坐标
* right:右侧坐标
* bottom:下方坐标
*/
func drawTreeNode(tree:FCTree, row:FCTreeRow, column:FCTreeColumn, node:FCTreeNode, paint:FCPaint, left:Double, top:Double, right:Double, bottom:Double) {
    if node.backColor != "none" {
        paint.fillRect(color:node.backColor, left:left, top:top, right:right, bottom:bottom)
    }
    if node.value.count > 0 {
        let tSize = paint.textSize(text:node.value, font:node.font)
        let tLeft = left + 2 + getTotalIndent(node:node)
        var wLeft = tLeft
        let cR = tree.checkBoxWidth / 3
        if tree.showCheckBox {
            wLeft += tree.checkBoxWidth
            if node.checked {
                paint.fillRect(color:node.textColor, left:tLeft + (tree.checkBoxWidth - cR) / 2, top:top + (tree.rowHeight - cR) / 2, right:tLeft + (tree.checkBoxWidth + cR) / 2, bottom:top + (tree.rowHeight + cR) / 2)
            } else {
                paint.drawRect(color:node.textColor, width:1, style:[], left:tLeft + (tree.checkBoxWidth - cR) / 2, top:top + (tree.rowHeight - cR) / 2, right:tLeft + (tree.checkBoxWidth + cR) / 2, bottom:top + (tree.rowHeight + cR) / 2)
            }
        }
        if node.childNodes.count > 0 {
            paint.beginPath()
            if node.collapsed {
                paint.addLine(x1:wLeft + (tree.collapsedWidth + cR) / 2, y1:top + tree.rowHeight / 2, x2:wLeft + (tree.collapsedWidth - cR) / 2, y2:top + (tree.rowHeight - cR) / 2)
                paint.addLine(x1:wLeft + (tree.collapsedWidth - cR) / 2, y1:top + (tree.rowHeight - cR) / 2, x2:wLeft + (tree.collapsedWidth - cR) / 2, y2:top + (tree.rowHeight + cR) / 2)
                paint.addLine(x1:wLeft + (tree.collapsedWidth - cR) / 2, y1:top + (tree.rowHeight + cR) / 2, x2:wLeft + (tree.collapsedWidth + cR) / 2, y2:top + tree.rowHeight / 2)
            } else {
                paint.addLine(x1:wLeft + (tree.collapsedWidth - cR) / 2, y1:top + (tree.rowHeight - cR) / 2, x2:wLeft + (tree.collapsedWidth + cR) / 2, y2:top + (tree.rowHeight - cR) / 2)
                paint.addLine(x1:wLeft + (tree.collapsedWidth + cR) / 2, y1:top + (tree.rowHeight - cR) / 2, x2:wLeft + tree.collapsedWidth / 2, y2:top + (tree.rowHeight + cR) / 2)
                paint.addLine(x1:wLeft + tree.collapsedWidth / 2, y1:top + (tree.rowHeight + cR) / 2, x2:wLeft + (tree.collapsedWidth - cR) / 2, y2:top + (tree.rowHeight - cR) / 2)
            }
            paint.fillPath(color:node.textColor)
            paint.closePath()
            wLeft += tree.collapsedWidth
        }
        
        if tSize.cx > column.width {
            paint.drawTextAutoEllipsis(text:node.value, color:node.textColor, font:node.font, left:wLeft, top:top + tree.rowHeight / 2 - tSize.cy / 2, right:wLeft + column.width, bottom:top + tree.rowHeight / 2 - tSize.cy / 2)
        } else {
            paint.drawText(text:node.value, color:node.textColor, font:node.font, x:wLeft, y:top + tree.rowHeight / 2 - tSize.cy / 2)
        }
    }
}

/*
* 绘制树
* tree:树
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawTree(tree:FCTree, paint:FCPaint, clipRect:FCRect) {
    var cTop = -tree.scrollV + tree.headerHeight
    //绘制行
    var colLeft:Double = 0
    if tree.columns.count > 0{
        for i in 0...tree.columns.count - 1{
            if tree.columns[i].widthStr.count > 0{
                let newWidthStr = tree.columns[i].widthStr.replacingOccurrences(of: "%", with: "")
                tree.columns[i].width = Double(StringToFloat(str:newWidthStr)) * tree.size.cx / 100
            }
            let colRect = FCRect(left:colLeft, top:0, right:colLeft + tree.columns[i].width, bottom:tree.headerHeight)
            tree.columns[i].bounds = colRect
            tree.columns[i].index = i
            colLeft += tree.columns[i].width
        }
    }
    updateTreeRowIndex(tree:tree)
    if tree.rows.count > 0{
        for i in 0...tree.rows.count - 1{
            let row = tree.rows[i]
            if row.visible {
                let rTop = cTop, rBottom = cTop + tree.rowHeight
                if rBottom >= 0 && cTop <= tree.size.cy {
                    for j in 0...row.cells.count - 1{
                        let node = row.cells[j]
                        var treeColumn = node.getColumn()
                        if !treeColumn.isNotEmpty {
                            treeColumn = tree.columns[j]
                        }
                        if treeColumn.visible {
                            let nodeWidth = treeColumn.width
                            let nodeHeight = tree.rowHeight
                            let cRect = FCRect(left:treeColumn.bounds.left - tree.scrollH, top:rTop, right:treeColumn.bounds.left + nodeWidth - tree.scrollH, bottom:rTop + nodeHeight)
                            if cRect.right >= 0 && cRect.left < tree.size.cx {
                                if tree.hasPaintTreeNodeEvent{
                                    tree.onPaintTreeNode(tree, row, treeColumn, node, paint, cRect.left, cRect.top, cRect.right, cRect.bottom)
                                }else if paint.hasPaintTreeNodeEvent{
                                    paint.onPaintTreeNode(tree, row, treeColumn, node, paint, cRect.left, cRect.top, cRect.right, cRect.bottom)
                                }else{
                                    drawTreeNode(tree:tree, row:row, column:treeColumn, node:node, paint:paint, left:cRect.left, top:cRect.top, right:cRect.right, bottom:cRect.bottom)
                                }
                            }
                        }
                    }
                }
                if cTop > tree.size.cy {
                    break
                }
                cTop += tree.rowHeight
            }
        }
    }
}

/*
* 绘制滚动条
* tree:树
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawTreeScrollBar(tree:FCTree, paint:FCPaint, clipRect:FCRect) {
    tree.hScrollIsVisible = false
    tree.vScrollIsVisible = false
    if tree.showHScrollBar {
        let contentWidth = getTreeContentWidth(tree:tree)
        if contentWidth > 0 && contentWidth > tree.size.cx {
            let sLeft = tree.scrollH / contentWidth * tree.size.cx
            var sRight = (tree.scrollH + tree.size.cx) / contentWidth * tree.size.cx
            if sRight - sLeft < tree.scrollSize {
                sRight = sLeft + tree.scrollSize
            }
            if tree.getPaint().getTouchMoveView() == tree && (tree.hoverScrollHButton || tree.downScrollHButton) {
                paint.fillRect(color:tree.scrollBarHoveredColor, left:sLeft, top:tree.size.cy - tree.scrollSize, right:sRight, bottom:tree.size.cy)
            }else {
                paint.fillRect(color:tree.scrollBarColor, left:sLeft, top:tree.size.cy - tree.scrollSize, right:sRight, bottom:tree.size.cy)
            }
            tree.hScrollIsVisible = true
        }
    }
    if tree.showVScrollBar {
        let contentHeight = getTreeContentHeight(tree:tree)
        if contentHeight > 0 && contentHeight > tree.size.cy {
            let sTop = tree.headerHeight + tree.scrollV / contentHeight * (tree.size.cy - tree.headerHeight - tree.scrollSize)
            var sBottom = sTop + ((tree.size.cy - tree.headerHeight)) / contentHeight * (tree.size.cy - tree.headerHeight - tree.scrollSize)
            if sBottom - sTop < tree.scrollSize {
                sBottom = sTop + tree.scrollSize
            }
            if tree.getPaint().getTouchMoveView() == tree && (tree.hoverScrollVButton || tree.downScrollVButton) {
                paint.fillRect(color:tree.scrollBarHoveredColor, left:tree.size.cx - tree.scrollSize, top:sTop, right:tree.size.cx, bottom:sBottom)
            } else {
                paint.fillRect(color:tree.scrollBarColor, left:tree.size.cx - tree.scrollSize, top:sTop, right:tree.size.cx, bottom:sBottom)
            }
            tree.vScrollIsVisible = true
        }
    }
}

/*
* 获取内容的宽度
* tree:树
*/
func getTreeContentWidth(tree:FCTree)->Double{
    var cWidth:Double = 0
    if tree.columns.count > 0{
        for i in 0...tree.columns.count - 1{
            if tree.columns[i].visible {
                cWidth += tree.columns[i].width
            }
        }
    }
    return cWidth
}

/*
* 获取内容的高度
* tree:树
*/
func getTreeContentHeight(tree:FCTree)->Double{
    var cHeight:Double = 0
    if tree.rows.count > 0{
        for i in 0...tree.rows.count - 1{
            if tree.rows[i].visible {
                cHeight += tree.rowHeight
            }
        }
    }
    return cHeight
}

/*
* 树的鼠标移动方法
* tree: 树
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
*/
func touchMoveTree(tree:FCTree, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint) {
    tree.hoverScrollHButton = false
    tree.hoverScrollVButton = false
    let mp = FCPoint(x:firstPoint.x, y:firstPoint.y)
    if firstTouch {
        if tree.showHScrollBar || tree.showVScrollBar {
            if tree.downScrollHButton {
                let contentWidth = getTreeContentWidth(tree:tree)
                let subX = (mp.x - tree.startPoint.x) / tree.size.cx * contentWidth
                var newScrollH = tree.startScrollH + subX
                if newScrollH < 0 {
                    newScrollH = 0
                } else if newScrollH > contentWidth - tree.size.cx {
                    newScrollH = contentWidth - tree.size.cx
                }
                tree.scrollH = newScrollH
                tree.getPaint().cancelClick = true
                return

            } else if tree.downScrollVButton {
                let contentHeight = getTreeContentHeight(tree:tree)
                let subY = (mp.y - tree.startPoint.y) / (tree.size.cy - tree.headerHeight - tree.scrollSize) * contentHeight
                var newScrollV = tree.startScrollV + subY
                if newScrollV < 0 {
                    newScrollV = 0
                } else if newScrollV > contentHeight - (tree.size.cy - tree.headerHeight - tree.scrollSize) {
                    newScrollV = contentHeight - (tree.size.cy - tree.headerHeight - tree.scrollSize)
                }
                tree.scrollV = newScrollV
                tree.getPaint().cancelClick = true
                return
            }
        }
        if tree.allowDragScroll {
            let contentWidth = getTreeContentWidth(tree:tree)
            if contentWidth > tree.size.cx {
                let subX = tree.startPoint.x - mp.x
                var newScrollH = tree.startScrollH + subX
                if newScrollH < 0 {
                    newScrollH = 0
                } else if newScrollH > contentWidth - tree.size.cx {
                    newScrollH = contentWidth - tree.size.cx
                }
                tree.scrollH = newScrollH
                if subX > 5 || subX < -5 {
                    tree.getPaint().cancelClick = true
                }
            }
            let contentHeight = getTreeContentHeight(tree:tree)
            if contentHeight > tree.size.cy {
                let subY = tree.startPoint.y - mp.y
                var newScrollV = tree.startScrollV + subY
                if newScrollV < 0 {
                    newScrollV = 0
                } else if newScrollV > contentHeight - (tree.size.cy - tree.headerHeight - tree.scrollSize) {
                    newScrollV = contentHeight - (tree.size.cy - tree.headerHeight - tree.scrollSize)
                }
                tree.scrollV = newScrollV
                if subY > 5 || subY < -5 {
                    tree.getPaint().cancelClick = true
                }
            }
        }
    } else {
        if tree.showHScrollBar {
            let contentWidth = getTreeContentWidth(tree:tree)
            if contentWidth > 0 && contentWidth > tree.size.cx {
                let sLeft = tree.scrollH / contentWidth * tree.size.cx
                var sRight = (tree.scrollH + tree.size.cx) / contentWidth * tree.size.cx
                if sRight - sLeft < tree.scrollSize {
                    sRight = sLeft + tree.scrollSize
                }
                if mp.x >= sLeft && mp.x <= sRight && mp.y >= tree.size.cy - tree.scrollSize && mp.y <= tree.size.cy {
                    tree.hoverScrollHButton = true
                    return
                } else {
                    tree.hoverScrollHButton = false
                }
            }
        }
        if tree.showVScrollBar {
            let contentHeight = getTreeContentHeight(tree:tree)
            if contentHeight > 0 && contentHeight > tree.size.cy {
                let sTop = tree.headerHeight + tree.scrollV / contentHeight * (tree.size.cy - tree.headerHeight - tree.scrollSize)
                var sBottom = tree.headerHeight + (tree.scrollV + (tree.size.cy - tree.headerHeight - tree.scrollSize)) / contentHeight * (tree.size.cy - tree.headerHeight - tree.scrollSize)
                if sBottom - sTop < tree.scrollSize {
                    sBottom = sTop + tree.scrollSize
                }
                if mp.x >= tree.size.cx - tree.scrollSize && mp.x <= tree.size.cx && mp.y >= sTop && mp.y <= sBottom {
                    tree.hoverScrollVButton = true
                    return
                } else {
                    tree.hoverScrollVButton = false
                }
            }
        }
    }
}

/*
* 树的鼠标按下方法
* tree: 树
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
* clicks:点击次数
*/
func touchDownTree(tree:FCTree, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint, clicks:Int) {
    let mp = FCPoint(x:firstPoint.x, y:firstPoint.y)
    tree.startPoint = mp
    tree.touchDownTime = getTickCount()
    tree.downScrollHButton = false
    tree.downScrollVButton = false
    tree.scrollAddSpeed = 0
    tree.isScrolling = false
    if tree.showHScrollBar {
        let contentWidth = getTreeContentWidth(tree:tree)
        if contentWidth > 0 && contentWidth > tree.size.cx {
            let sLeft = tree.scrollH / contentWidth * tree.size.cx
            var sRight = (tree.scrollH + tree.size.cx) / contentWidth * tree.size.cx
            if sRight - sLeft < tree.scrollSize {
                sRight = sLeft + tree.scrollSize
            }
            if mp.x >= sLeft && mp.x <= sRight && mp.y >= tree.size.cy - tree.scrollSize && mp.y <= tree.size.cy {
                tree.downScrollHButton = true
                tree.startScrollH = tree.scrollH
                return
            }
        }
    }
    if tree.showVScrollBar {
        let contentHeight = getTreeContentHeight(tree:tree)
        if contentHeight > 0 && contentHeight > tree.size.cy {
            let sTop = tree.headerHeight + tree.scrollV / contentHeight * (tree.size.cy - tree.headerHeight - tree.scrollSize)
            var sBottom = tree.headerHeight + (tree.scrollV + (tree.size.cy - tree.headerHeight - tree.scrollSize)) / contentHeight * (tree.size.cy - tree.headerHeight - tree.scrollSize)
            if sBottom - sTop < tree.scrollSize {
                sBottom = sTop + tree.scrollSize
            }
            if mp.x >= tree.size.cx - tree.scrollSize && mp.x <= tree.size.cx && mp.y >= sTop && mp.y <= sBottom {
                tree.downScrollVButton = true
                tree.startScrollV = tree.scrollV
                return
            }
        }
    }
    if tree.allowDragScroll {
        tree.startScrollH = tree.scrollH
        tree.startScrollV = tree.scrollV
    }
}

/*
* 表格的鼠标抬起方法
* tree: 树
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
* clicks:点击次数
*/
func touchUpTree(tree:FCTree, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint, clicks:Int) {
    tree.hoverScrollHButton = false
    tree.hoverScrollVButton = false
    if tree.getPaint().cancelClick{
        return
    }
    if firstTouch {
        if tree.allowDragScroll {
            let touchUpTime = getTickCount()
            let diff = Double(touchUpTime - tree.touchDownTime)
            //加速滚动
            if diff > 0 && diff < 250 {
                let sub1 = Int(30 * ((abs(firstPoint.y - tree.startPoint.y)) / 20) / diff * 10)
                let sub2 = Int(30 * ((abs(firstPoint.x - tree.startPoint.x)) / 20) / diff * 10)
                if abs(sub1) > abs(sub2) {
                    if firstPoint.y < tree.startPoint.y {
                        tree.scrollAddSpeed += sub1
                    } else {
                        tree.scrollAddSpeed -= sub1
                    }
                    tree.scrollDirection = 0
                } else {
                    if firstPoint.x < tree.startPoint.x {
                        tree.scrollAddSpeed += sub2
                    } else {
                        tree.scrollAddSpeed -= sub2
                    }
                    tree.scrollDirection = 1
                }
                tree.isScrolling = true
                if abs(tree.scrollAddSpeed) > 0 {
                    tree.getPaint().cancelClick = true
                }
            }
        }
    }
    tree.downScrollHButton = false
    tree.downScrollVButton = false
    let cLeft = -tree.scrollH
    var cTop = -tree.scrollV + tree.headerHeight
    if tree.rows.count > 0{
        for i in 0...tree.rows.count - 1{
            let row = tree.rows[i]
            if row.visible {
                if firstPoint.y >= cTop && firstPoint.y <= cTop + tree.rowHeight {
                    let node = row.cells[0]
                    let tLeft = cLeft + 2 + getTotalIndent(node:node)
                    var wLeft = tLeft
                    if tree.showCheckBox {
                        wLeft += tree.checkBoxWidth
                        if firstPoint.x < wLeft {
                            checkOrUnCheckTreeNode(node:node, checked:!node.checked)
                            invalidateView(view:tree)
                            break
                        }
                    }
                    if node.childNodes.count > 0 {
                        wLeft += tree.collapsedWidth
                        if firstPoint.x < wLeft {
                            node.collapsed = !node.collapsed
                            hideOrShowTreeNode(node:node, visible:!node.collapsed)
                            invalidateView(view:tree)
                            break
                        }
                    }
                    if tree.hasClickTreeNodeEvent{
                      tree.onClickTreeNode(tree, node, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
                    }
                    else if tree.getPaint().hasClickTreeNodeEvent{
                      tree.getPaint().onClickTreeNode(tree, node, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
                    }
                }
                cTop += tree.rowHeight
            }
        }
    }
}

/*
* 更新行的索引
* tree:树
*/
func updateTreeRowIndex(tree:FCTree) {
    if tree.rows.count > 0{
        for i in 0...tree.rows.count - 1{
            tree.rows[i].index = i
        }
    }
}


/*
* 获取最后一行的索引
* node:树节点
*/
func getTreeLastNodeRowIndex(node:FCTreeNode)->Int {
    var rowIndex = node.getRow().index
    if node.childNodes.count > 0{
        for i in 0...node.childNodes.count - 1{
            let rIndex = getTreeLastNodeRowIndex(node:node.childNodes[i])
            if rowIndex < rIndex {
                rowIndex = rIndex
            }
        }
    }
    return rowIndex
}

/*
* 添加节点
* tree:树
* node:要添加的节点
* parentNode:父节点
*/
func appendTreeNode(tree:FCTree, node:FCTreeNode, parentNode:FCTreeNode) {
    if !parentNode.isNotEmpty {
        let newRow = FCTreeRow()
        tree.rows.append(newRow)
        node.setRow(r:newRow)
        newRow.cells.append(node)
        tree.childNodes.append(node)
    } else {
        let newRow = FCTreeRow()
        if parentNode.childNodes.count == 0 {
            tree.rows.insert(newRow, at:parentNode.getRow().index + 1)
        } else {
            tree.rows.insert(newRow, at:getTreeLastNodeRowIndex(node:parentNode) + 1)
        }
        node.setParentNode(node: parentNode)
        node.indent = tree.indent
        node.setRow(r:newRow)
        newRow.cells.append(node)
        parentNode.childNodes.append(node)
        if parentNode.collapsed {
            newRow.visible = false
        }
    }
    updateTreeRowIndex(tree:tree)
}

/*
* 移除节点
* tree:树
* node:要添加的节点
*/
func removeTreeNode (tree:FCTree, node:FCTreeNode) {
    //移除相互关系
    if !node.isNotEmpty {
        let nodesSize = tree.childNodes.count
        if nodesSize > 0{
            for i in 0...nodesSize - 1{
                if tree.childNodes[i] == node {
                    tree.childNodes.remove(at:1)
                    break
                }
            }
        }
    } else {
        let nodesSize = node.getParentNode().childNodes.count
        if nodesSize > 0{
            for i in 0...nodesSize - 1{
                if node.getParentNode().childNodes[i] == node {
                    node.getParentNode().childNodes.remove(at:i)
                    break
                }
            }
        }
    }
    //移除行
    tree.rows.remove(at:node.getRow().index)
    updateTreeRowIndex(tree:tree)
}

/*
* 展开或折叠节点
* node:节点
* visible:是否可见
*/
func hideOrShowTreeNode(node:FCTreeNode, visible:Bool) {
    if node.childNodes.count > 0{
        for i in 0...node.childNodes.count - 1{
            node.childNodes[i].getRow().visible = visible
            hideOrShowTreeNode(node:node.childNodes[i], visible:visible)
        }
    }
}

/*
* 选中或反选节点
* node:节点
* checked:是否选中
*/
func checkOrUnCheckTreeNode(node:FCTreeNode, checked:Bool) {
    node.checked = checked
    if node.childNodes.count > 0 {
        for i in 0...node.childNodes.count - 1{
            checkOrUnCheckTreeNode(node:node.childNodes[i], checked: checked)
        }
    }
}

/*
*展开树的节点
*tree:树
*/
func expendTree(tree:FCTree){
    if tree.childNodes.count > 0{
        for i in 0...tree.childNodes.count - 1{
            tree.childNodes[i].collapsed = false
            hideOrShowTreeNode(node:tree.childNodes[i], visible:true)
        }
    }
}

/*
*折叠树的节点
*tree:树
*/
func collapseTree(tree:FCTree){
    if tree.childNodes.count > 0{
        for i in 0...tree.childNodes.count - 1{
            tree.childNodes[i].collapsed = true
            hideOrShowTreeNode(node:tree.childNodes[i], visible:false)
        }
    }
}

/*
* 树的鼠标滚轮方法
* tree:树
* delta:滚轮值
*/
func touchWheelTree(tree:FCTree, delta:Int) {
    var oldScrollV = tree.scrollV
    if delta > 0 {
        oldScrollV -= tree.rowHeight
    } else if delta < 0 {
        oldScrollV += tree.rowHeight
    }
    let contentHeight = getTreeContentHeight(tree:tree)
    if contentHeight < tree.size.cy {
        tree.scrollV = 0
    } else {
        if oldScrollV < 0 {
            oldScrollV = 0
        } else if oldScrollV > contentHeight - tree.size.cy + tree.headerHeight + tree.scrollSize {
            oldScrollV = contentHeight - tree.size.cy + tree.headerHeight + tree.scrollSize
        }
        tree.scrollV = oldScrollV
    }
}

/*
 * 检查树的滚动
 * tree:树视图
 */
func checkTreeScroll(tree:FCTree){
    if tree.isScrolling {
        var sub = Int(tree.scrollAddSpeed / 10)
        if sub == 0 && tree.scrollAddSpeed > 1 {
            sub = 1
        } else if sub == 0 && tree.scrollAddSpeed < -1 {
            sub = -1
        }
        tree.scrollAddSpeed -= sub
        if abs(sub) <= 1 {
            tree.scrollAddSpeed = 0
            tree.isScrolling = false
            invalidateView(view:tree)
        } else {
            var oldScrollV = tree.scrollV + Double(tree.scrollAddSpeed)
            var oldScrollH = tree.scrollH + Double(tree.scrollAddSpeed)
            if tree.scrollDirection == 0 {
                let contentHeight = getTreeContentHeight(tree:tree)
                if contentHeight < tree.size.cy {
                    tree.scrollV = 0
                } else {
                    if oldScrollV < 0 {
                        oldScrollV = 0
                    } else if oldScrollV > contentHeight - tree.size.cy + tree.headerHeight + tree.scrollSize {
                        oldScrollV = contentHeight - tree.size.cy + tree.headerHeight + tree.scrollSize
                    }
                    tree.scrollV = oldScrollV
                }
            } else {
                let contentWidth = getTreeContentHeight(tree:tree)
                if contentWidth < tree.size.cx {
                    tree.scrollH = 0
                } else {
                    if oldScrollH < 0 {
                        oldScrollH = 0
                    } else if oldScrollH > contentWidth - tree.size.cx {
                        oldScrollH = contentWidth - tree.size.cx
                    }
                    tree.scrollH = oldScrollH
                }
            }
            invalidateView(view:tree)
        }
    }
}

/*
 * 自动适应位置和大小
 * menu:菜单
 */
func adjustMenu(menu: FCMenu) {
    resetLayoutDiv(layout:menu)
    if menu.autoSize {
        let contentHeight = getDivContentHeight(div:menu)
        let maximumHeight = menu.maximumSize.cy
        menu.size.cy = min(contentHeight, maximumHeight)
    }
    let mPoint = FCPoint(x:menu.location.x, y:menu.location.y)
    let mSize = menu.size
    let paint = menu.getPaint()
    let nSize = FCSize(cx:paint.size.cx / paint.scaleFactorX, cy:paint.size.cy / paint.scaleFactorY)
    if mPoint.x < 0 {
        mPoint.x = 0
    }
    if mPoint.y < 0 {
        mPoint.y = 0
    }
    if mPoint.x + mSize.cx > nSize.cx {
        mPoint.x = nSize.cx - mSize.cx
    }
    if mPoint.y + mSize.cy > nSize.cy {
        mPoint.y = nSize.cy - mSize.cy
    }
    menu.location = mPoint
    menu.scrollV = 0
}

/*
 * 添加菜单项
 * item:菜单项
 * menu:菜单
 */
func addMenuItem(item:FCMenuItem, menu:FCMenu) {
    addViewToParent(view:item, parent:menu)
    item.setParentMenu(m:menu)
    menu.items.append(item)
}

/*
 * 添加菜单项
 * item:菜单项
 * parentItem:父菜单项
 */
func addMenuItemToParent(item: FCMenuItem, parentItem: FCMenuItem) {
    item.setParentItem(m:parentItem)
    if !parentItem.getDropDownMenu().isNotEmpty {
        let newMenu = FCMenu()
        parentItem.setDropDownMenu(m: newMenu)
        addView(view:parentItem.getDropDownMenu(), paint:parentItem.getPaint())
    }
    item.setParentMenu(m:parentItem.getDropDownMenu())
    addViewToParent(view:item, parent:parentItem.getDropDownMenu())
    parentItem.items.append(item)
    parentItem.getDropDownMenu().items.append(item)
}

/*
 * 控制菜单的显示隐藏
 * paint:绘图对象
 */
func checkShowMenu(paint: FCPaint) {
    var paintAll = false
    var clickItem = false
    if paint.views.count > 0{
        for i in 0...paint.views.count - 1{
            let view = paint.views[i]
            if view.viewType == "menu" {
                let menu = view as! FCMenu
                if view.visible {
                    if view == paint.getTouchDownView() {
                        clickItem = true
                    }
                    if(menu.items.count > 0){
                        for j in 0...menu.items.count - 1{
                            let item = menu.items[j]
                            if item == paint.getTouchDownView() {
                                clickItem = true
                                break
                            }
                        }
                    }
                }
            }
        }
        if !clickItem {
            for i in 0...paint.views.count - 1{
                let view = paint.views[i]
                if view.viewType == "menu" {
                    view.visible = false
                    paintAll = true
                }
            }
        }
    }
    if paintAll {
        invalidate(paint:paint)
    }
}

/*
 * 关闭网格视图
 * items:菜单集合
 */
func closeMenus(items: Array<FCMenuItem>)->Bool {
    let itemSize = items.count
    var close = false
    if itemSize > 0{
        for i in 0...itemSize - 1{
            let item = items[i]
            let subItems = item.items
            if closeMenus(items:subItems) {
                close = true
            }
            let dropDownMenu = item.getDropDownMenu()
            if dropDownMenu.isNotEmpty && dropDownMenu.visible {
                dropDownMenu.visible = false
                close = true
            }
        }
    }
    return close
}

/*
 * 鼠标移动到菜单项
 * item 菜单项
 */
func touchMoveMenuItem(item: FCMenuItem) {
    let parentItem = item.getParentItem()
    var items = [FCMenuItem]()
    if parentItem.isNotEmpty {
        if parentItem.getDropDownMenu().isNotEmpty {
            items = parentItem.getDropDownMenu().items
        }
    } else {
        if item.getParentMenu().isNotEmpty {
            items = item.getParentMenu().items
        }
    }
    if closeMenus(items:items){
        
    }
    if item.items.count > 0 {
        let dropDownMenu = item.getDropDownMenu()
        //获取位置和大小
        if dropDownMenu.isNotEmpty && !dropDownMenu.visible {
            let layoutStyle = dropDownMenu.layoutStyle
            let location = FCPoint(x:clientX(view:item) + item.size.cx, y:clientY(view:item))
            if layoutStyle == "lefttoright" || layoutStyle == "righttoleft" {
                location.x = clientX(view:item)
                location.y = clientY(view:item) + item.size.cy
            }
            //设置弹出位置
            dropDownMenu.location = location
            dropDownMenu.visible = true
            adjustMenu(menu:dropDownMenu)
            invalidate(paint:item.getPaint())
            return
        }
    }
    invalidate(paint:item.getPaint())
}

/*
* 重绘按钮
* item:菜单项
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawMenuItem(item: FCMenuItem, paint: FCPaint, clipRect: FCRect) {
    if item == paint.getTouchDownView() {
        if item.pushedColor != "none" {
            paint.fillRect(color:item.pushedColor, left:0, top:0, right:item.size.cx, bottom:item.size.cy)
        } else {
            if item.backColor != "none"{
                paint.fillRect(color:item.backColor, left:0, top:0, right:item.size.cx, bottom:item.size.cy)
            }
        }
    } else if item == paint.getTouchMoveView() {
        if item.hoveredColor != "none" {
            paint.fillRect(color:item.hoveredColor, left:0, top:0, right:item.size.cx, bottom:item.size.cy)
        } else {
            if item.backColor != "none" {
                paint.fillRect(color:item.backColor, left:0, top:0, right:item.size.cx,  bottom:item.size.cy)
            }
        }
    }
    else if item.backColor != "none" {
        paint.fillRect(color:item.backColor, left:0, top:0, right:item.size.cx, bottom:item.size.cy)
    }
    if item.textColor != "none" && item.text.count > 0 {
        let tSize = paint.textSize(text:item.text, font:item.font)
        paint.drawText(text:item.text, color:item.textColor, font:item.font, x:(item.size.cx - tSize.cx) / 2, y:(item.size.cy - tSize.cy) / 2)
    }
    if item.borderColor != "none" {
        paint.drawRect(color:item.borderColor, width:item.borderWidth, style:[], left:0, top:0, right:item.size.cx, bottom:item.size.cy)
    }
    if item.items.count > 0 {
        let tR = 5.0
        paint.beginPath()
        paint.addLine(x1:item.size.cx - 2, y1:item.size.cy / 2, x2:item.size.cx - 2 - tR * 2, y2:item.size.cy / 2 - tR)
        paint.addLine(x1:item.size.cx - 2 - tR * 2, y1:item.size.cy / 2 - tR, x2:item.size.cx - 2 - tR * 2, y2:item.size.cy / 2 + tR)
        paint.addLine(x1:item.size.cx - 2 - tR * 2, y1:item.size.cy / 2 + tR, x2:item.size.cx - 2, y2:item.size.cy / 2)
        paint.fillPath(color:item.textColor)
        paint.closePath()
    }
}

/*
 * 点击菜单项
 * item:菜单项
 */
func clickMenuItem(item: FCMenuItem) {
    var paintAll = false
    if item.getParentMenu().isNotEmpty {
        if item.getParentMenu().getComboBox().isNotEmpty {
            var index = -1
            if item.getParentMenu().items.count > 0{
                for i in 0...item.getParentMenu().items.count - 1{
                    if item.getParentMenu().items[i] == item {
                        index = i
                        break
                    }
                }
                item.getParentMenu().getComboBox().selectedIndex = index
                item.getParentMenu().getComboBox().text = item.getParentMenu().items[index].text
                paintAll = true
            }
        }
    }
    if item.items.count == 0 {
        for i in 0...item.getPaint().views.count - 1{
            let subView = item.getPaint().views[i]
            if subView.viewType == "menu" {
                if subView.visible {
                    subView.visible = false
                    paintAll = true
                }
            }
        }
    }
    if paintAll {
        invalidate(paint:item.getPaint())
    }
}

/*
* 重绘按钮
* comboBox:下拉列表
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawComboBox(comboBox: FCComboBox, paint: FCPaint, clipRect: FCRect) {
    if comboBox.backColor != "none" {
        paint.fillRect(color:comboBox.backColor, left:0, top:0, right:comboBox.size.cx, bottom:comboBox.size.cy)
    }
    if comboBox.textColor != "none" && comboBox.text.count > 0 {
        let tSize = paint.textSize(text:comboBox.text, font:comboBox.font)
        paint.drawText(text:comboBox.text, color:comboBox.textColor, font:comboBox.font, x:5, y:(comboBox.size.cy - tSize.cy) / 2)
    }
    if comboBox.borderColor != "none" {
        paint.drawRect(color:comboBox.borderColor, width:comboBox.borderWidth, style:[], left:0, top:0, right:comboBox.size.cx, bottom:comboBox.size.cy)
    }
    let tR = 5.0
    paint.beginPath()
    paint.addLine(x1:comboBox.size.cx - 5 - tR * 2, y1:comboBox.size.cy / 2 - tR, x2:comboBox.size.cx - 5, y2:comboBox.size.cy / 2 - tR)
    paint.addLine(x1:comboBox.size.cx - 5, y1:comboBox.size.cy / 2 - tR, x2:comboBox.size.cx - 5 - tR, y2:comboBox.size.cy / 2 + tR)
    paint.addLine(x1:comboBox.size.cx - 5 - tR, y1:comboBox.size.cy / 2 + tR, x2:comboBox.size.cx - 5 - tR * 2, y2:comboBox.size.cy / 2 - tR)
    paint.fillPath(color:comboBox.textColor)
    paint.closePath()
}

/*
 * 点击下拉菜单
 * comboBox:下拉菜单
 */
func clickComboBox(comboBox: FCComboBox) {
    let showX = clientX(view:comboBox)
    let showY = clientY(view:comboBox) + comboBox.size.cy
    comboBox.getDropDownMenu().location = FCPoint(x:showX, y:showY)
    comboBox.getDropDownMenu().visible = true
    adjustMenu(menu:comboBox.getDropDownMenu())
    invalidate(paint:comboBox.getPaint())
}

/*
* 计算直线参数
* mp:坐标
* x1:横坐标1
* y1:纵坐标1
* x2:横坐标2
* y2:纵坐标2
* oX:坐标起始X
* oY:坐标起始Y
*/
func lineXY(chart:FCChart, x1:Double, y1:Double, x2:Double, y2:Double, oX:Double, oY:Double) {
    chart.kChart = 0
    chart.bChart = 0
    if (x1 - oX) != (x2 - oX) {
        chart.kChart = ((y2 - oY) - (y1 - oY)) / ((x2 - oX) - (x1 - oX))
        chart.bChart = (y1 - oY) - chart.kChart * (x1 - oX)
    }
}

/*
* 判断是否选中直线
* mp:坐标
* x1:横坐标1
* y1:纵坐标1
* x2:横坐标2
* y2:纵坐标2
*/
func selectLine(chart:FCChart, mp:FCPoint, x1:Double, y1:Double, x2:Double, y2:Double)->Bool{
    if !(chart.kChart == 0 && chart.bChart == 0) {
        if mp.y / (mp.x * chart.kChart + chart.bChart) >= 0.9 && mp.y / (mp.x * chart.kChart + chart.bChart) <= 1.1 {
            return true
        }
    } else {
        if mp.x >= x1 - chart.plotPointSizeChart && mp.x <= x1 + chart.plotPointSizeChart {
            return true
        }
    }
    return false
}

/*
* 判断是否选中射线
* mp:坐标
* x1:横坐标1
* y1:纵坐标1
* x2:横坐标2
* y2:纵坐标2
*/
func selectRay(chart:FCChart, mp:FCPoint, x1:Double, y1:Double, x2:Double, y2:Double)->Bool{
    if !(chart.kChart == 0 && chart.bChart == 0) {
        if mp.y / (mp.x * chart.kChart + chart.bChart) >= 0.9 && mp.y / (mp.x * chart.kChart + chart.bChart) <= 1.1 {
            if x1 >= x2 {
                if mp.x > x1 + chart.plotPointSizeChart {
                    return false
                }
            } else if (x1 < x2) {
                if mp.x < x1 - chart.plotPointSizeChart{
                    return false
                }
            }
            return true
        }
    } else {
        if mp.x >= x1 - chart.plotPointSizeChart && mp.x <= x1 + chart.plotPointSizeChart {
            if y1 >= y2 {
                if mp.y <= y1 - chart.plotPointSizeChart {
                    return true
                }
            } else {
                if mp.y >= y1 - chart.plotPointSizeChart {
                    return true
                }
            }
        }
    }
    return false
}

/*
* 判断是否选中线段
* mp:坐标
* x1:横坐标1
* y1:纵坐标1
* x2:横坐标2
* y2:纵坐标2
*/
func selectSegment(chart:FCChart, mp:FCPoint, x1:Double, y1:Double, x2:Double, y2:Double)->Bool{
    lineXY(chart:chart, x1:x1, y1:y1, x2:x2, y2:y2, oX:0, oY:0)
    let smallX = x1 <= x2 ? x1 : x2
    let smallY = y1 <= y2 ? y1 : y2
    let bigX = x1 > x2 ? x1 : x2
    let bigY = y1 > y2 ? y1 : y2
    if mp.x >= smallX - 2 && mp.x <= bigX + 2 && mp.y >= smallY - 2 && mp.y <= bigY + 2 {
        if chart.kChart != 0 || chart.bChart != 0 {
            if mp.y / (mp.x * chart.kChart + chart.bChart) >= 0.9 && mp.y / (mp.x * chart.kChart + chart.bChart) <= 1.1 {
                return true
            }
        } else {
            if mp.x >= x1 - chart.plotPointSizeChart && mp.x <= x1 + chart.plotPointSizeChart {
                return true
            }
        }
    }
    return false
}

/*
* 根据三点计算圆心
* x1:横坐标1
* y1:纵坐标1
* x2:横坐标2
* y2:纵坐标2
* x3:横坐标3
* y3:纵坐标3
*/
func ellipseOR(chart:FCChart, x1:Double, y1:Double, x2:Double, y2:Double, x3:Double, y3:Double) {
chart.oXChart = ((y3 - y1) * (y2 * y2 - y1 * y1 + x2 * x2 - x1 * x1) + (y2 - y1) * (y1 * y1 - y3 * y3 + x1 * x1 - x3 * x3))
        / (2 * (x2 - x1) * (y3 - y1) - 2 * (x3 - x1) * (y2 - y1))
    chart.oYChart = ((x3 - x1) * (x2 * x2 - x1 * x1 + y2 * y2 - y1 * y1) + (x2 - x1) * (x1 * x1 - x3 * x3 + y1 * y1 - y3 * y3))
        / (2 * (y2 - y1) * (x3 - x1) - 2 * (y3 - y1) * (x2 - x1))
    chart.rChart = sqrt((x1 - chart.oXChart) * (x1 - chart.oXChart) + (y1 - chart.oYChart) * (y1 - chart.oYChart))
}

/*
* 判断点是否在椭圆上
* x:横坐标
* y:纵坐标
* oX:坐标起始X
* oY:坐标起始Y
* a:椭圆参数a
* b:椭圆参数b
*/
func ellipseHasPoint(ix:Double, iy:Double, oX:Double, oY:Double,  a:Double, b:Double)->Bool {
    var x = ix
    var y = iy
    x -= oX
    y -= oY
    if a == 0 && b == 0 && x == 0 && y == 0 {
        return true
    }
    if a == 0 {
        if x == 0 && y >= -b && y <= b {
            return false
        }
    }
    if b == 0 {
        if y == 0 && x >= -a && x <= a {
            return true
        }
    }
    if (x * x) / (a * a) + (y * y) / (b * b) >= 0.8 && (x * x) / (a * a) + (y * y) / (b * b) <= 1.2 {
        return true
    }
    return false
}

/*
* 计算线性回归
* list:集合
*/
func linearRegressionEquation(chart:FCChart, list:[Double]){
    var sumX:Double = 0
    var sumY:Double = 0
    var sumUp:Double = 0
    var sumDown:Double = 0
    var xAvg:Double = 0
    var yAvg:Double = 0
    chart.kChart = 0
    chart.bChart = 0
    let length = list.count
    if length > 1 {
        for i in 0...length - 1 {
            sumX += Double(i + 1)
            sumY += list[i]
        }
        xAvg = sumX / Double(length)
        yAvg = sumY / Double(length)
        for i in 0...length - 1 {
            let di:Double = Double(i)
            sumUp += (di + 1.0 - xAvg) * (list[i] - yAvg)
            sumDown += (di + 1.0 - xAvg) * (di + 1.0 - xAvg)
        }
        chart.kChart = sumUp / sumDown
        chart.bChart = yAvg - chart.kChart * xAvg
    }
}

/*
* 计算最大值
* list:集合
*/
func maxValue(list:[Double])->Double{
    let length = list.count
    var max:Double = 0
    if length > 0{
        for i in 0...length - 1 {
          if i == 0 {
              max = list[i]
          }
          else {
              if max < list[i] {
                  max = list[i]
              }
          }
        }
    }
    return max
}

/*
* 计算最小值
* list:集合
*/
func minValue(list:[Double])->Double{
    let length = list.count
    var min:Double = 0
    if length > 0{
        for i in 0...length - 1 {
            if i == 0 {
                min = list[i]
            }
            else {
                if min > list[i] {
                    min = list[i]
                }
            }
        }
    }
    return min
}

/*
* 计算平均值
* list:集合
*/
func avgValue(list:[Double])->Double{
    var sum:Double = 0
    let length = list.count
    if length > 0 {
        for i in 0...length - 1 {
            sum += list[i]
        }
        return sum / Double(length)
    }
    return 0
}

/*
* 计算平行四边形参数
* x1:横坐标1
* y1:纵坐标1
* x2:横坐标2
* y2:纵坐标2
* x3:横坐标3
* y3:纵坐标3
*/
func parallelogram(chart:FCChart, x1:Double, y1:Double, x2:Double, y2:Double, x3:Double, y3:Double) {
    chart.x4Chart = x1 + x3 - x2
    chart.y4Chart = y1 + y3 - y2
}

/*
* 计算斐波那契数列
* index:索引
*/
func fibonacciValue(index:Int)->Int {
    if index < 1 {
        return 0
    }
    else {
        var vList = [Int]()
        for _ in 0...index - 1{
            vList.append(0)
        }
        var result = 0
        for i in 0...index - 1 {
            if i == 0 || i == 1 {
                vList[i] = 1
            }
            else {
                vList[i] = vList[i - 1] + vList[i - 2]
            }
        }
        result = vList[index - 1]
        return result
    }
}

/*
* 获取图表的区域
* chart: 图表
* plot: 画线
*/
func getCandleRange(chart:FCChart, plot:FCPlot) {
    var bIndex = getChartIndexByDate(chart: chart, date:plot.key1)
    var eIndex = getChartIndexByDate(chart:chart, date:plot.key2)
    let tempBIndex = min(bIndex, eIndex)
    let tempEIndex = max(bIndex, eIndex)
    bIndex = tempBIndex
    eIndex = tempEIndex
    var highList = [Double]()
    var lowList = [Double]()
    for i in bIndex...eIndex{
        highList.append(chart.data[i].high)
        lowList.append(chart.data[i].low)
    }
    chart.nHighChart = maxValue(list:highList)
    chart.nLowChart = minValue(list:lowList)
}

/*
* 获取百分比线的刻度
* y1: 纵坐标1
* y2: 纵坐标2
*/
func getPercentParams(y1:Double, y2:Double)->[Double] {
    var y0 = 0.0, y25 = 0.0, y50 = 0.0, y75 = 0.0, y100 = 0.0
    y0 = y1
    y25 = y1 <= y2 ? y1 + (y2 - y1) / 4 : y2 + (y1 - y2) * 3 / 4
    y50 = y1 <= y2 ? y1 + (y2 - y1) / 2 : y2 + (y1 - y2) / 2
    y75 = y1 <= y2 ? y1 + (y2 - y1) * 3 / 4 : y2 + (y1 - y2) / 4
    y100 = y2
    var list = [Double]()
    list.append(y0)
    list.append(y25)
    list.append(y50)
    list.append(y75)
    list.append(y100)
    return list
}

/*
* 根据坐标计算矩形
* x1:横坐标1
* y1:纵坐标1
* x2:横坐标2
* y2:纵坐标2
*/
func rectangleXYWH(chart:FCChart, x1:Double, y1:Double, x2:Double, y2:Double) {
    chart.xChart = x1 < x2 ? x1 : x2
    chart.yChart = y1 < y2 ? y1 : y2
    chart.wChart = x1 - x2 > 0 ? x1 - x2 : x2 - x1
    chart.hChart = y1 - y2 > 0 ? y1 - y2 : y2 - y1
    if chart.wChart <= 0 {
        chart.wChart = 4
    }
    if chart.hChart <= 0 {
        chart.hChart = 4
    }
}

/*
 * 计算最大值
 * @param {Object} ticks 最高价数组
 * @param {Object} days
 */
func hhvValue(ticks:[Double], days:Int)->[Double] {
    var hhv = [Double]()
    var max:Double = ticks[0]
    if ticks.count > 0{
        for i in 0...ticks.count - 1{
            if i >= days {
                max = ticks[i]
                var j = i
                while j > i - days{
                    if max < ticks[j] {
                        max = ticks[j]
                    }
                    j -= 1
                }
                hhv.append(max)
            } else {
                if max < ticks[i] {
                    max = ticks[i]
                }
                hhv.append(max)
            }
        }
    }
    return hhv
}

/*
 * 计算最小值
 * @param {Object} ticks 最低价数组
 * @param {Object} days
 */
func llvValue(ticks:[Double], days:Int)->[Double] {
    var llv = [Double]()
    var min = ticks[0]
    if ticks.count > 0{
        for i in 0...ticks.count - 1{
            if i >= days {
                min = ticks[i]
                var j = i
                while j > i - days{
                    if min > ticks[j] {
                        min = ticks[j]
                    }
                    j -= 1
                }
                llv.append(min)
            } else {
                if min > ticks[i] {
                    min = ticks[i]
                }
                llv.append(min)
            }
        }
    }
    return llv
}

/*
* REF函数
* ticks:数据
* days:日数
*/
func refValue(ticks:[Double], days:Int)->[Double] {
    var refArr = [Double]()
    let length = ticks.count
    if length > 0{
        for i in 0...length - 1{
            var ref:Double = 0
            if i >= days {
                ref = ticks[i - days]
            } else {
                ref = ticks[0]
            }
            refArr.append(ref)
        }
    }
    return refArr
}

/*
* 获取TRIX的数据
* ticks:数据
*/
func getTRIXData(ticks:[Double], m:Int, trixArr:inout [Double], matrixArr:inout [Double]){
    let length = ticks.count
    var mtrArr = [Double]()
    var emaArr1 = [Double]()
    emaArr1.append(ticks[0])
    for i in 1...length - 1{
        emaArr1.append(getEMA(n:m, value:ticks[i], lastEMA:emaArr1[i - 1]))
    }

    var emaArr2 = [Double]()
    emaArr2.append(emaArr1[0])
    for i in 1...length - 1{
        emaArr2.append(getEMA(n:m, value:emaArr1[i], lastEMA:emaArr2[i - 1]))
    }

    mtrArr.append(emaArr2[0])
    for i in 1...length - 1{
        mtrArr.append(getEMA(n:m, value:emaArr2[i], lastEMA:mtrArr[i - 1]))
    }

    let ref = refValue(ticks:mtrArr, days:1)
    for i in 0...length - 1{
        let trix = 100.0 * (mtrArr[i] - ref[i]) / ref[i]
        trixArr.append(trix)
    }

    let matrixArrCopy = maValue(ticks:trixArr, days:m)
    for i in 0...matrixArrCopy.count - 1{
        matrixArr.append(matrixArrCopy[i])
    }
}

/*
* 获取方差数据
*/
func standardDeviationSum(listValue:[Double], avgValue:Double)->Double{
    let targetValue = listValue[listValue.count - 1]
    var sumValue = (targetValue - avgValue) * (targetValue - avgValue)
    for i in 0...listValue.count - 2{
        let ileft = listValue[i]
        sumValue = sumValue + (ileft - avgValue) * (ileft - avgValue)
    }
    return sumValue
}

/*
 * 计算boll指标,ma的周期为20日
 *
 * @method BOLL
 * @param {Array} ticks
 * 一维数组类型，每个元素为当前Tick的收盘价格
 * @return {Object} 返回一个包含upper mid lower属性的对象,每个属性对应的类型为{Array[Number]}
 */
func getBollData(ticks:[Double], maDays:Int, ups:inout [Double], mas:inout [Double], lows:inout [Double]){
    let tickBegin:Int = maDays - 1
    var maSum:Double  = 0
    var p:Double = 0
    for i in 0...ticks.count - 1{
        let c = ticks[i]
        var ma:Double = 0
        var md:Double = 0
        var bstart:Int = 0
        var mdSum:Double = 0
        maSum = maSum + c
        if i >= tickBegin{
            maSum = maSum - p
            ma = maSum / Double(maDays)
            bstart = i - tickBegin
            p = ticks[bstart]
            mas.append(ma)
            bstart = i - tickBegin
            p = ticks[bstart]
            var values = [Double]()
            for j in bstart...bstart + maDays  - 1{
                values.append(ticks[j])
            }
            mdSum = standardDeviationSum(listValue:values, avgValue:ma)
            md = sqrt(mdSum / Double(maDays))
            ups.append(ma + 2 * md)
            lows.append(ma - 2 * md)
        }
        else{
            ma = maSum / Double(i + 1)
            mas.append(ma)
            var values = [Double]()
            for j in bstart...bstart + maDays - 1{
                values.append(ticks[j])
            }
            mdSum = standardDeviationSum(listValue:values, avgValue:ma)
            md = sqrt(mdSum / Double(i + 1))
            ups.append(ma + 2 * md)
            lows.append(ma - 2 * md)
        }
    }
}

/*
 *
 * 计算kdj指标,rsv的周期为9日
 *
 * @method KDJ
 * @param {Array} ticks
 * 二维数组类型，其中内层数组包含三个元素值，第一个值表示当前Tick的最高价格，第二个表示当前Tick的最低价格，第三个表示当前Tick的收盘价格
 * @return {Object} 返回一个包含k d j属性的对象,每个属性对应的类型为{Array[Number]}
 */
func getKDJData(highArr:[Double], lowArr:[Double], closeArr:[Double], n:Int, m1:Int, m2:Int, ks:inout [Double], ds:inout [Double], js:inout [Double]) {
    var rsvs = [Double]()
    var lastK:Double = 0
    var lastD:Double = 0
    var curK:Double = 0
    var curD:Double = 0
    for i in 0...closeArr.count - 1{
        var highList = [Double]()
        var lowList = [Double]()
        var startIndex : Int = i - n
        if startIndex < 0{
            startIndex = 0
        }
        for j in startIndex...i{
            highList.append(highArr[j])
            lowList.append(lowArr[j])
        }
  
        let close = closeArr[i]
        var maxHigh:Double = 0
        var minLow:Double = 0
        for m in 0...lowList.count - 1{
            let high = highList[m]
            let low = lowList[m]
            if high > maxHigh{
                maxHigh = high
            }
            if low < minLow{
                minLow = low
            }
        }
        if maxHigh == minLow{
            rsvs.append(0)
        }
        else{
            rsvs.append((close - minLow) / (maxHigh - minLow) * 100)
        }
        if i == 0{
            lastK = rsvs[i]
            lastD = rsvs[i]
        }
        curK = Double(m1 - 1) / Double(m1) * lastK + 1.0 / Double(m1) * rsvs[i]
        ks.append(curK)
        lastK = curK

        curD = Double(m2 - 1) / Double(m1) * lastD + 1.0 / Double(m2) * curK
        ds.append(curD)
        lastD = curD

        js.append(3.0 * curK - 2.0 * curD)
    }
}

/*
 *
 * 计算rsi指标,分别返回以6日，12日，24日为参考基期的RSI值
 *
 * @method RSI
 * @param {Array} ticks
 * 一维数组类型，每个元素为当前Tick的收盘价格
 * @return {Object} 返回一个包含rsi6 rsi12 rsi24属性的对象,每个属性对应的类型为{Array[Number]}
 */
func getRSIData(ticks:[Double], n1:Int, n2:Int, n3:Int, rsi1:inout [Double], rsi2:inout  [Double], rsi3:inout [Double]) {
    var lastClosePx = ticks[0]
    var lastSm1:Double = 0
    var lastSa1:Double = 0
    var lastSm2:Double = 0
    var lastSa2:Double = 0
    var lastSm3:Double = 0
    var lastSa3:Double = 0
    for i in 0...ticks.count - 1{
        let c = ticks[i]
        let m = max(c - lastClosePx, 0)
        let a = abs(c - lastClosePx)
        if i == 0{
            lastSm1 = 0
            lastSa1 = 0
            rsi1.append(0)
        }
        else{
            lastSm1 = (m + Double(n1 - 1) * lastSm1) / Double(n1)
            lastSa1 = (a + Double(n1 - 1) * lastSa1) / Double(n1)
            if lastSa1 != 0{
                rsi1.append(lastSm1 / lastSa1 * 100)
            }
            else{
                rsi1.append(0)
            }
        }
        if i == 0{
            lastSm2 = 0
            lastSa2 = 0
            rsi2.append(0)
        }
        else{
            lastSm2 = (m + Double(n2 - 1) * lastSm2) / Double(n2)
            lastSa2 = (a + Double(n2 - 1) * lastSa2) / Double(n2)
            if lastSa2 != 0{
                rsi2.append(lastSm2 / lastSa2 * 100)
            }
            else{
                rsi2.append(0)
            }
        }
        if i == 0{
            lastSm3 = 0
            lastSa3 = 0
            rsi3.append(0)
        }
        else{
            lastSm3 = (m + Double(n3 - 1) * lastSm3) / Double(n3)
            lastSa3 = (a + Double(n3 - 1) * lastSa3) / Double(n3)
            if lastSa3 != 0{
                rsi3.append(lastSm3 / lastSa3 * 100)
            }
            else{
                rsi3.append(0.0)
            }
        }
        lastClosePx = c
    }
}

/*
 * MA数据计算
 * @param {Object} ticks 收盘价数组
 * @param {Object} days 天数
 */
func maValue(ticks:[Double], days:Int)->[Double] {
    var maSum:Double = 0
    var mas = [Double]()
    var last:Double = 0
    for i in 0...ticks.count - 1{
        var ma:Double = 0
        if i >= days {
            last = ticks[i - days]
            maSum = maSum + ticks[i] - last
            ma = maSum / Double(days)
        } else {
            maSum += ticks[i]
            ma = maSum / Double(i + 1)
        }
        mas.append(ma)
    }
    return mas
}

/*
 * 计算ROC数据
 * @param {Object} ticks 收盘价数组
 */
func getRocData(ticks:[Double], n:Int, m:Int, roc:inout [Double], maroc:inout [Double]) {
    for i in 0...ticks.count - 1{
        var currRoc:Double = 0
        if i >= n{
            currRoc = 100.0 * (ticks[i] - ticks[i - n]) / ticks[i - n]
            roc.append(currRoc)
        }
        else{
            currRoc = 100.0 * (ticks[i] - ticks[0]) / ticks[0]
            roc.append(currRoc)
        }
    }
    let marocMA = maValue(ticks: roc, days:m)
    for i in 0...marocMA.count - 1{
        maroc.append(marocMA[i])
    }
}

/*
 * 获取BIAS的数据
 * @param {Array} ticks 收盘价数组
 * @return
 */
func getBIASData(ticks:[Double], n1:Int, n2:Int, n3:Int, bias1Arr:inout [Double], bias2Arr:inout [Double], bias3Arr:inout [Double]) {
    let ma1 = maValue(ticks:ticks, days:n1)
    let ma2 = maValue(ticks:ticks, days:n2)
    let ma3 = maValue(ticks:ticks, days:n3)
    for i in 0...ticks.count - 1{
        let b1 = (ticks[i] - ma1[i]) / ma1[i] * 100.0
        let b2 = (ticks[i] - ma2[i]) / ma2[i] * 100.0
        let b3 = (ticks[i] - ma3[i]) / ma3[i] * 100.0
        bias1Arr.append(b1)
        bias2Arr.append(b2)
        bias3Arr.append(b3)
    }
}

/*
 * 计算BBI(多空指标)
 * @param {Object} ticks
 */
func getBBIData(ticks:[Double], n1:Int, n2:Int, n3:Int, n4:Int, bbiArr:inout [Double]) {
    let ma3 = maValue(ticks:ticks, days:n1)
    let ma6 = maValue(ticks:ticks, days:n2)
    let ma12 = maValue(ticks:ticks, days:n3)
    let ma24 = maValue(ticks:ticks, days:n4)
    for i in 0...ticks.count - 1{
        let bbi = (ma3[i] + ma6[i] + ma12[i] + ma24[i]) / 4.0
        bbiArr.append(bbi)
    }
}

/*
 * 计算WR(威廉指标)
 * @param {Array} ticks 含最高价,最低价, 收盘价的二维数组
 * @param {Object} days
 */
func getWRData(highArr:[Double], lowArr:[Double], closeArr:[Double], n1:Int, n2:Int, wr1Arr:inout [Double], wr2Arr:inout [Double]){
    let highArr1 = hhvValue(ticks:highArr, days:n1)
    let highArr2 = hhvValue(ticks:highArr, days:n2)
    let lowArr1 = llvValue(ticks:lowArr, days:n1)
    let lowArr2 = llvValue(ticks:lowArr, days:n2)
    for i in 0...closeArr.count - 1{
        let high1 = highArr1[i]
        let low1 = lowArr1[i]
        let high2 = highArr2[i]
        let low2 = lowArr2[i]
        let close = closeArr[i]
        let wr1 = 100.0 * (high1 - close) / (high1 - low1)
        let wr2 = 100.0 * (high2 - close) / (high2 - low2)
        wr1Arr.append(wr1)
        wr2Arr.append(wr2)
    }
}

/*
 * 计算DMA（平均差）
 * @param {Object} ticks 收盘价数组
 */
func getDMAData(ticks:[Double], n1:Int, n2:Int, difArr:inout [Double], difmaArr:inout [Double]) {
    let ma10 = maValue(ticks:ticks, days:n1)
    let ma50 = maValue(ticks:ticks, days:n2)
    for i in 0...ticks.count - 1{
        let dif = ma10[i] - ma50[i]
        difArr.append(dif)
    }
    let difma = maValue(ticks:difArr, days:n1)
    for i in 0...difma.count - 1{
        difmaArr.append(difma[i])
    }
}

/*
 * CCI(顺势指标)计算  CCI（N日）=（TP－MA）÷MD÷0.015
 * @param {Object} ticks 带最高价，最低价，收盘价的二维数组
 */
func getCCIData(highArr:[Double], lowArr:[Double], closeArr:[Double], n:Int, cciArr:inout [Double]) {
    var tpArr = [Double]()
    for i in 0...closeArr.count - 1{
        tpArr.append((closeArr[i] + highArr[i] + lowArr[i]) / 3.0)
    }
    let maClose = maValue(ticks:closeArr, days:n)

    var mdArr = [Double]()
    for i in 0...closeArr.count - 1{
        mdArr.append(maClose[i] - closeArr[i])
    }
    let maMD = maValue(ticks:mdArr, days:n)
    for i in 0...closeArr.count - 1{
        var cci:Double = 0
        if maMD[i] > 0{
            cci = (tpArr[i] - maClose[i]) / (maMD[i] * 0.015)
        }
        cciArr.append(cci)
    }
}

/*
* 图表的鼠标按下方法
* chart: 图表
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
*/
func touchDownChart(chart:FCChart, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint) {
    chart.touchDownPointChart = FCPoint(x:firstPoint.x, y:firstPoint.y)
    chart.crossStopIndex = getChartIndex(chart:chart, mp:firstPoint)
    chart.targetOldX = 0;
    chart.targetOldX2 = 0;
    chart.selectShape = ""
    chart.selectShapeEx = ""
    chart.sPlot = [FCPlot]()
    if chart.data.count > 0{
        let selectedPlot = selectPlot(chart:chart, mp:firstPoint)
        if selectedPlot.isNotEmpty{
            chart.setSelectedPlot(plot:selectedPlot)
        }
        if !chart.getSelectedPlot().isNotEmpty {
            selectShape(chart:chart, mp:firstPoint)
        }
    }
    if chart.getPaint().isDoubleClick{
        chart.showCrossLine = !chart.showCrossLine
    }
}

/*
*左滚
*chart:图表
*step:步长
*/
func scrollLeftChart(chart:FCChart, step:Int){
    chart.targetOldX = 0
    chart.targetOldX2 = 0
    var dStep = step
    if chart.showCrossLine{
        chart.crossStopIndex = chart.crossStopIndex - dStep
        if chart.crossStopIndex >= chart.firstVisibleIndex{
            dStep = 0
        }
        else if chart.crossStopIndex < 0{
            chart.crossStopIndex = 0
        }
    }
    if dStep > 0{
        let subIndex = chart.lastVisibleIndex - chart.firstVisibleIndex
        var fIndex = chart.firstVisibleIndex - dStep
        if fIndex < 0{
            fIndex = 0
        }
        let eIndex = fIndex + subIndex
        chart.firstVisibleIndex = fIndex
        chart.lastVisibleIndex = eIndex
    }
    checkChartLastVisibleIndex(chart:chart)
    if chart.hasCalculateChartMaxMinEvent{
        chart.onCalculateChartMaxMin(chart)
    }
    else if chart.getPaint().hasCalculateChartMaxMinEvent{
        chart.getPaint().onCalculateChartMaxMin(chart)
    }else{
        calculateChartMaxMin(chart:chart)
    }
}

/*
*右滚
*chart:图表
*step:步长
*/
func scrollRightChart(chart:FCChart, step:Int){
    chart.targetOldX = 0
    chart.targetOldX2 = 0
    var dStep = step
    let dataCount = chart.data.count
    if chart.showCrossLine{
        chart.crossStopIndex = chart.crossStopIndex + dStep
        if chart.crossStopIndex <= chart.lastVisibleIndex{
            dStep = 0
        }
        else if chart.crossStopIndex > dataCount - 1{
            chart.crossStopIndex = dataCount - 1
        }
    }
    if dStep > 0{
        let subIndex = chart.lastVisibleIndex - chart.firstVisibleIndex
        var eIndex = chart.lastVisibleIndex + dStep
        if eIndex > dataCount - 1{
            eIndex = dataCount - 1
        }
        let fIndex = eIndex - subIndex
        chart.firstVisibleIndex = fIndex
        chart.lastVisibleIndex = eIndex
    }
    checkChartLastVisibleIndex(chart:chart)
    if chart.hasCalculateChartMaxMinEvent{
        chart.onCalculateChartMaxMin(chart)
    }
    else if chart.getPaint().hasCalculateChartMaxMinEvent{
        chart.getPaint().onCalculateChartMaxMin(chart)
    }else{
        calculateChartMaxMin(chart:chart)
    }
}

/*
*图表的键盘按下事件
*chart:图表
*key:按键
*/
func keyDownChart(chart:FCChart, key:Int){
    if key == 38{
        zoomOutChart(chart:chart)
    }else if key == 40{
        zoomInChart(chart:chart)
    }else if key == 37{
        scrollLeftChart(chart:chart, step:1)
    }else if key == 39{
        scrollRightChart(chart:chart, step:1)
    }
}

/*
* 添加画线
* chart: 图表
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
*/
func addPlotDefault(chart:FCChart, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint) {
    let mp = FCPoint(x:firstPoint.x, y:firstPoint.y)
    if mp.y < getCandleDivHeight(chart:chart) {
        let touchIndex = getChartIndex(chart:chart, mp:mp)
        if touchIndex >= chart.firstVisibleIndex && touchIndex <= chart.lastVisibleIndex {
            if (chart.addingPlotChart == "FiboTimezone") {
                let fIndex = touchIndex
                let fDate = getChartDateByIndex(chart:chart, index:fIndex)
                let y = getChartValue(chart:chart, point:mp)
                let newPlot = FCPlot()
                if chart.getPaint().defaultUIStyle == "light" {
                    newPlot.lineColor = "rgb(0,0,0)"
                    newPlot.pointColor = "rgba(0,0,0,125)"
                } else {
                    newPlot.lineColor = "rgb(255,255,255)"
                    newPlot.pointColor = "rgba(255,255,255,125)"
                }
                newPlot.key1 = fDate
                newPlot.value1 = y
                newPlot.plotType = chart.addingPlotChart
                chart.plots.append(newPlot)
                chart.sPlot = [FCPlot]()
                let selectedPlot = selectPlot(chart:chart, mp:mp)
                if selectedPlot.isNotEmpty{
                    chart.setSelectedPlot(plot: selectedPlot)
                }
            }
            else if chart.addingPlotChart == "Triangle" || chart.addingPlotChart == "CircumCycle" || chart.addingPlotChart == "ParalleGram" || chart.addingPlotChart == "AngleLine" || chart.addingPlotChart == "Parallel" || chart.addingPlotChart == "SymmetricTriangle"{
                let eIndex = touchIndex
                let bIndex = eIndex - 5
                if bIndex >= 0 {
                    let fDate = getChartDateByIndex(chart:chart, index:bIndex)
                    let sDate = getChartDateByIndex(chart:chart, index:eIndex)
                    let y = getChartValue(chart:chart, point:mp)
                    let newPlot = FCPlot()
                    if chart.getPaint().defaultUIStyle == "light" {
                        newPlot.lineColor = "rgb(0,0,0)"
                        newPlot.pointColor = "rgba(0,0,0,125)"
                    } else {
                        newPlot.lineColor = "rgb(255,255,255)"
                        newPlot.pointColor = "rgba(255,255,255,125)"
                    }
                    newPlot.key1 = fDate
                    newPlot.value1 = y
                    newPlot.key2 = sDate
                    newPlot.value2 = y
                    newPlot.key3 = sDate
                    newPlot.value3 = chart.candleMin + (chart.candleMax - chart.candleMin) / 2
                    newPlot.plotType = chart.addingPlotChart
                    chart.plots.append(newPlot)
                    chart.sPlot = [FCPlot]()
                    let selectedPlot = selectPlot(chart:chart, mp:mp)
                    if selectedPlot.isNotEmpty{
                        chart.setSelectedPlot(plot: selectedPlot)
                    }
                }
            } else {
                let eIndex = touchIndex
                let bIndex = eIndex - 5
                if bIndex >= 0 {
                    let fDate = getChartDateByIndex(chart:chart, index:bIndex)
                    let sDate = getChartDateByIndex(chart:chart, index:eIndex)
                    let y = getChartValue(chart:chart, point:mp)
                    let newPlot = FCPlot()
                    if chart.getPaint().defaultUIStyle == "light" {
                        newPlot.lineColor = "rgb(0,0,0)"
                        newPlot.pointColor = "rgba(0,0,0,125)"
                    } else {
                        newPlot.lineColor = "rgb(255,255,255)"
                        newPlot.pointColor = "rgba(255,255,255,125)"
                    }
                    newPlot.key1 = fDate
                    newPlot.value1 = y
                    newPlot.key2 = sDate
                    newPlot.value2 = y
                    newPlot.plotType = chart.addingPlotChart
                    chart.plots.append(newPlot)
                    chart.sPlot = [FCPlot]()
                    let selectedPlot = selectPlot(chart:chart, mp:mp)
                    if selectedPlot.isNotEmpty{
                        chart.setSelectedPlot(plot: selectedPlot)
                    }
                }
            }
        }
    }
}

/*
* 图表的鼠标移动方法
* chart: 图表
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
*/
func touchMoveChart(chart:FCChart, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint) {
    if chart.data.count == 0 {
        return
    }
    let mp = FCPoint(x:firstPoint.x, y:firstPoint.y)
    chart.crossStopIndex = getChartIndex(chart:chart, mp:mp)
    chart.touchPosition = mp
    chart.targetOldX = 0;
    chart.targetOldX2 = 0;
    let sPlot = chart.getSelectedPlot()
    if firstTouch && sPlot.isNotEmpty {
        let newIndex = getChartIndex(chart:chart, mp:mp)
        if newIndex >= 0 && newIndex < chart.data.count {
            let newDate = getChartDateByIndex(chart:chart, index:newIndex)
            let newValue = getCandleDivValue(chart:chart, point:mp)
            if chart.selectPlotPoint == 0 {
                sPlot.key1 = newDate
                sPlot.value1 = newValue
            } else if chart.selectPlotPoint == 1 {
                sPlot.key2 = newDate
                sPlot.value2 = newValue
            } else if chart.selectPlotPoint == 2 {
                sPlot.key3 = newDate
                sPlot.value3 = newValue
            }
            else if chart.startMovePlot {
                let bValue = getCandleDivValue(chart:chart, point:chart.touchDownPointChart)
                let bIndex = getChartIndex(chart:chart, mp:chart.touchDownPointChart)
                if sPlot.key1 > 0 {
                    sPlot.value1 = sPlot.startValue1 + (newValue - bValue)
                    let startIndex1 = getChartIndexByDate(chart:chart, date:sPlot.startKey1)
                    var newIndex1 = startIndex1 + (newIndex - bIndex)
                    if newIndex1 < 0 {
                        newIndex1 = 0
                    }
                    else if newIndex1 > chart.data.count - 1 {
                        newIndex1 = chart.data.count - 1
                    }
                    sPlot.key1 = getChartDateByIndex(chart:chart, index:newIndex1)
                }
                if sPlot.key2 > 0 {
                    sPlot.value2 = sPlot.startValue2 + (newValue - bValue)
                    let startIndex2 = getChartIndexByDate(chart:chart, date:sPlot.startKey2)
                    var newIndex2 = startIndex2 + (newIndex - bIndex)
                    if newIndex2 < 0 {
                        newIndex2 = 0
                    }
                    else if newIndex2 > chart.data.count - 1 {
                        newIndex2 = chart.data.count - 1
                    }
                    sPlot.key2 = getChartDateByIndex(chart:chart, index:newIndex2)
                }
                if sPlot.key3 > 0 {
                    sPlot.value3 = sPlot.startValue3 + (newValue - bValue)
                    let startIndex3 = getChartIndexByDate(chart:chart, date:sPlot.startKey3)
                    var newIndex3 = startIndex3 + (newIndex - bIndex)
                    if newIndex3 < 0 {
                        newIndex3 = 0
                    }
                    else if newIndex3 > chart.data.count - 1 {
                        newIndex3 = chart.data.count - 1
                    }
                    sPlot.key3 = getChartDateByIndex(chart:chart, index:newIndex3)
                }
            }
        }
        return
    }
    if firstTouch && secondTouch {
        if firstPoint.x > secondPoint.x {
            chart.firstTouchPointCacheChart = secondPoint
            chart.secondTouchPointCacheChart = firstPoint
        } else {
            chart.firstTouchPointCacheChart = firstPoint
            chart.secondTouchPointCacheChart = secondPoint
        }
        if chart.firstTouchIndexCacheChart == -1 || chart.secondTouchIndexCacheChart == -1 {
            chart.firstTouchIndexCacheChart = getChartIndex(chart:chart, mp:chart.firstTouchPointCacheChart)
            chart.secondTouchIndexCacheChart = getChartIndex(chart:chart, mp:chart.secondTouchPointCacheChart)
            chart.firstIndexCacheChart = chart.firstVisibleIndex
            chart.lastIndexCacheChart = chart.lastVisibleIndex
        }
    } else if firstTouch {
        chart.secondTouchIndexCacheChart = -1
        if chart.firstTouchIndexCacheChart == -1 {
            chart.firstTouchPointCacheChart = firstPoint
            chart.firstTouchIndexCacheChart = getChartIndex(chart:chart, mp:chart.firstTouchPointCacheChart)
            chart.firstIndexCacheChart = chart.firstVisibleIndex
            chart.lastIndexCacheChart = chart.lastVisibleIndex
            chart.firstPaddingTop = chart.candlePaddingTop
            chart.firtstPaddingBottom = chart.candlePaddingBottom
        }
    }

    if firstTouch && secondTouch {
        if chart.firstTouchIndexCacheChart != -1 && chart.secondTouchIndexCacheChart != -1 {
            var fPoint = FCPoint(x:firstPoint.x, y:firstPoint.y)
            var sPoint = FCPoint(x:secondPoint.x, y:secondPoint.y)
            if firstPoint.x > secondPoint.x {
                fPoint = secondPoint
                sPoint = firstPoint
            }
            let subX = abs(sPoint.x - fPoint.x)
            let subIndex = abs(chart.secondTouchIndexCacheChart - chart.firstTouchIndexCacheChart)
            if subX > 0 && subIndex > 0 {
                var newScalePixel = subX / Double(subIndex)
                if newScalePixel >= 3 {
                    let intScalePixel:Double = Double(Int(newScalePixel))
                    newScalePixel = intScalePixel
                }
                if newScalePixel != chart.hScalePixel {
                    var newFirstIndex = chart.firstTouchIndexCacheChart
                    var thisX = fPoint.x
                    thisX -= newScalePixel
                    while thisX > chart.leftVScaleWidth + newScalePixel{
                        newFirstIndex -= 1
                        if newFirstIndex < 0 {
                            newFirstIndex = 0
                            break
                        }
                        thisX -= newScalePixel
                    }

                    thisX = sPoint.x
                    var newSecondIndex = chart.secondTouchIndexCacheChart
                    thisX += newScalePixel
                    while thisX < chart.size.cx - chart.rightVScaleWidth - newScalePixel {
                        newSecondIndex += 1
                        if (newSecondIndex > chart.data.count - 1) {
                            newSecondIndex = chart.data.count - 1
                            break
                        }
                        thisX += newScalePixel
                    }
                    setChartVisibleIndex(chart: chart, firstVisibleIndex: newFirstIndex, lastVisibleIndex: newSecondIndex)
                    let maxVisibleRecord = getChartMaxVisibleCount(chart:chart, hScalePixel:chart.hScalePixel, pureH:getChartWorkAreaWidth(chart:chart))
                    while maxVisibleRecord < chart.lastVisibleIndex - chart.firstVisibleIndex + 1
                        && chart.lastVisibleIndex > chart.firstVisibleIndex {
                        chart.lastVisibleIndex -= 1
                    }
                    checkChartLastVisibleIndex(chart:chart)
                    resetChartVisibleRecord(chart:chart)
                    if chart.hasCalculateChartMaxMinEvent{
                        chart.onCalculateChartMaxMin(chart)
                    }
                    else if chart.getPaint().hasCalculateChartMaxMinEvent{
                        chart.getPaint().onCalculateChartMaxMin(chart)
                    }else{
                        calculateChartMaxMin(chart:chart)
                    }
                }
            }
        }
    } else if firstTouch {
        if !chart.autoFillHScale{
            let subIndex = Int((chart.firstTouchPointCacheChart.x - firstPoint.x) / chart.hScalePixel)
            if chart.allowDragChartDiv {
                chart.candlePaddingTop = chart.firstPaddingTop - (chart.firstTouchPointCacheChart.y - firstPoint.y)
                chart.candlePaddingBottom = chart.firtstPaddingBottom + (chart.firstTouchPointCacheChart.y - firstPoint.y)
            }
            var fIndex = chart.firstIndexCacheChart + subIndex
            var lIndex = chart.lastIndexCacheChart + subIndex
            if fIndex > chart.data.count - 1{
                fIndex = chart.data.count - 1
                lIndex = chart.data.count - 1
            }
            chart.firstVisibleIndex = fIndex
            chart.lastVisibleIndex = lIndex
            checkChartLastVisibleIndex(chart:chart)
            if chart.hasCalculateChartMaxMinEvent{
                chart.onCalculateChartMaxMin(chart)
            }
            else if chart.getPaint().hasCalculateChartMaxMinEvent{
                chart.getPaint().onCalculateChartMaxMin(chart)
            }else{
                calculateChartMaxMin(chart:chart)
            }
        }
    }
}

/*
* 选中直线
* chart: 图表
* mp:坐标
*/
func selectPlot(chart:FCChart, mp:FCPoint)->FCPlot {
    var sPlot = FCPlot()
    sPlot.isNotEmpty = false
    chart.startMovePlot = false
    chart.selectPlotPoint = -1
    if chart.plots.count > 0{
        for i in 0...chart.plots.count - 1{
            let plot = chart.plots[i]
            var index1 = 0, index2 = 0, index3 = 0
            var mpx1 = 0.0, mpy1 = 0.0, mpx2 = 0.0, mpy2 = 0.0, mpx3 = 0.0, mpy3 = 0.0
            //检查关键点
            if plot.key1 > 0 {
                index1 = getChartIndexByDate(chart:chart, date:plot.key1)
                mpx1 = getChartX(chart:chart, index:index1)
                mpy1 = getChartY(chart:chart, divIndex:0, value:plot.value1)
                if mp.x >= mpx1 - chart.plotPointSizeChart && mp.x <= mpx1 + chart.plotPointSizeChart && mp.y >= mpy1 - chart.plotPointSizeChart && mp.y <= mpy1 + chart.plotPointSizeChart {
                    sPlot = plot
                    chart.selectPlotPoint = 0
                    break
                }
            }
            if plot.key2 > 0 {
                index2 = getChartIndexByDate(chart:chart, date:plot.key2)
                mpx2 = getChartX(chart:chart, index:index2)
                mpy2 = getChartY(chart:chart, divIndex:0, value:plot.value2)
                if mp.x >= mpx2 - chart.plotPointSizeChart && mp.x <= mpx2 + chart.plotPointSizeChart && mp.y >= mpy2 - chart.plotPointSizeChart && mp.y <= mpy2 + chart.plotPointSizeChart {
                    sPlot = plot
                    chart.selectPlotPoint = 1
                    break
                }
            }
            if plot.key3 > 0 {
                index3 = getChartIndexByDate(chart:chart, date:plot.key3)
                mpx3 = getChartX(chart:chart, index:index3)
                mpy3 = getChartY(chart:chart, divIndex:0, value:plot.value3)
                if mp.x >= mpx3 - chart.plotPointSizeChart && mp.x <= mpx3 + chart.plotPointSizeChart && mp.y >= mpy3 - chart.plotPointSizeChart && mp.y <= mpy3 + chart.plotPointSizeChart {
                    sPlot = plot
                    chart.selectPlotPoint = 2
                    break
                }
            }
            //判断其余部分的选中
            if chart.selectPlotPoint == -1 {
                if plot.plotType == "Line" {
                    chart.startMovePlot = selectLine(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                }
                else if plot.plotType == "ArrowSegment"{
                    chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                }
                else if plot.plotType == "AngleLine" {
                    chart.startMovePlot = selectLine(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                    if !chart.startMovePlot {
                        chart.startMovePlot = selectLine(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:mpx3, y2:mpy3)
                    }
                }
                else if plot.plotType == "Parallel" {
                    chart.startMovePlot = selectLine(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                    if !chart.startMovePlot {
                        lineXY(chart:chart, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2, oX:0, oY:0)
                        let newB = mpy3 - chart.kChart * mpx3
                        if mpx2 == mpx1 {
                            if mp.x >= mpx3 - chart.plotPointSizeChart && mp.x <= mpx3 + chart.plotPointSizeChart {
                                chart.startMovePlot = true
                            }
                        } else {
                            let newX1 = chart.leftVScaleWidth
                            let newY1 = newX1 * chart.kChart + newB
                            let newX2 = chart.size.cx - chart.rightVScaleWidth
                            let newY2 = newX2 * chart.kChart + newB
                            chart.startMovePlot = selectLine(chart:chart, mp:mp, x1:newX1, y1:newY1, x2:newX2, y2:newY2)
                        }
                    }
                }
                else if plot.plotType == "LRLine" {
                    chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                }
                else if plot.plotType == "Segment" {
                    chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                } else if plot.plotType == "Ray" {
                    chart.startMovePlot = selectRay(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                }
                else if plot.plotType == "Triangle" {
                    chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                    if !chart.startMovePlot {
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx2, y1:mpy2, x2:mpx3, y2:mpy3)
                    }
                    if !chart.startMovePlot {
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:mpx3, y2:mpy3)
                    }
                }
                else if plot.plotType == "SymmetricTriangle" {
                    if mpx2 != mpx1 {
                        let a = (mpy2 - mpy1) / (mpx2 - mpx1)
                        let b = mpy1 - a * mpx1
                        let c = -a
                        let d = mpy3 - c * mpx3
                        let leftX = chart.leftVScaleWidth
                        var leftY = leftX * a + b
                        let rightX = chart.size.cx - chart.rightVScaleWidth
                        var rightY = rightX * a + b
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:leftX, y1:leftY, x2:rightX, y2:rightY)
                        if !chart.startMovePlot {
                            leftY = leftX * c + d
                            rightY = rightX * c + d
                            chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:leftX, y1:leftY, x2:rightX, y2:rightY)
                        }
                    } else {
                        let divHeight = getCandleDivHeight(chart:chart)
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx1, y1:0, x2:mpx1, y2:divHeight)
                        if !chart.startMovePlot {
                            chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx3, y1:0, x2:mpx3, y2:divHeight)
                        }
                    }
                }
                else if plot.plotType == "Rect" {
                    let sX1 = min(mpx1, mpx2)
                    let sY1 = min(mpy1, mpy2)
                    let sX2 = max(mpx1, mpx2)
                    let sY2 = max(mpy1, mpy2)
                    chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:sX1, y1:sY1, x2:sX2, y2:sY1)
                    if !chart.startMovePlot {
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:sX2, y1:sY1, x2:sX2, y2:sY2)
                    }
                    if !chart.startMovePlot {
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:sX1, y1:sY2, x2:sX2, y2:sY2)
                    }
                    if !chart.startMovePlot {
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:sX1, y1:sY1, x2:sX1, y2:sY2)
                    }
                }
                else if plot.plotType == "BoxLine" {
                    let sX1 = min(mpx1, mpx2)
                    let sY1 = min(mpy1, mpy2)
                    let sX2 = max(mpx1, mpx2)
                    let sY2 = max(mpy1, mpy2)
                    chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:sX1, y1:sY1, x2:sX2, y2:sY1)
                    if !chart.startMovePlot {
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:sX2, y1:sY1, x2:sX2, y2:sY2)
                    }
                    if !chart.startMovePlot {
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:sX1, y1:sY2, x2:sX2, y2:sY2)
                    }
                    if !chart.startMovePlot {
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:sX1, y1:sY1, x2:sX1, y2:sY2)
                    }
                }
                else if plot.plotType == "TironeLevels" {
                    let sX1 = min(mpx1, mpx2)
                    let sY1 = min(mpy1, mpy2)
                    let sX2 = max(mpx1, mpx2)
                    let sY2 = max(mpy1, mpy2)
                    chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:sX1, y1:sY1, x2:sX2, y2:sY1)
                    if !chart.startMovePlot {
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:sX1, y1:sY2, x2:sX2, y2:sY2)
                    }
                }
                else if plot.plotType == "QuadrantLines" {
                    let sX1 = min(mpx1, mpx2)
                    let sY1 = min(mpy1, mpy2)
                    let sX2 = max(mpx1, mpx2)
                    let sY2 = max(mpy1, mpy2)
                    chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:sX1, y1:sY1, x2:sX2, y2:sY1)
                    if !chart.startMovePlot {
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:sX1, y1:sY2, x2:sX2, y2:sY2)
                    }
                }
                else if plot.plotType == "GoldenRatio" {
                    let sY1 = min(mpy1, mpy2)
                    let sY2 = max(mpy1, mpy2)
                    var ranges = [Double]()
                    ranges.append(0)
                    ranges.append(0.236)
                    ranges.append(0.382)
                    ranges.append(0.5)
                    ranges.append(0.618)
                    ranges.append(0.809)
                    ranges.append(1)
                    ranges.append(1.382)
                    ranges.append(1.618)
                    ranges.append(2)
                    ranges.append(2.382)
                    ranges.append(2.618)
                    for j in 0...ranges.count - 1{
                        let newY = sY1 <= sY2 ? sY1 + (sY2 - sY1) * ranges[j] : sY2 + (sY1 - sY2) * (1 - ranges[j])
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:chart.leftVScaleWidth, y1:newY, x2:chart.size.cx - chart.rightVScaleWidth, y2:newY)
                        if chart.startMovePlot {
                            break
                        }
                    }
                }else if plot.plotType == "Cycle" {
                    let r = sqrt(abs((mpx2 - mpx1) * (mpx2 - mpx1) + (mpy2 - mpy1) * (mpy2 - mpy1)))
                    let round = (mp.x - mpx1) * (mp.x - mpx1) + (mp.y - mpy1) * (mp.y - mpy1)
                    if round / (r * r) >= 0.9 && round / (r * r) <= 1.1 {
                        chart.startMovePlot = true
                    }
                } else if plot.plotType == "CircumCycle" {
                    ellipseOR(chart:chart, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2, x3:mpx3, y3:mpy3)
                    let round = (mp.x - chart.oXChart) * (mp.x - chart.oXChart) + (mp.y - chart.oYChart) * (mp.y - chart.oYChart)
                    if round / (chart.rChart * chart.rChart) >= 0.9 && round / (chart.rChart * chart.rChart) <= 1.1 {
                        chart.startMovePlot = true
                    }
                }
                else if plot.plotType == "Ellipse" {
                    var x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0
                    if mpx1 <= mpx2 {
                        x1 = mpx2
                        y1 = mpy2
                        x2 = mpx1
                        y2 = mpy1
                    } else {
                        x1 = mpx1
                        y1 = mpy1
                        x2 = mpx2
                        y2 = mpy2
                    }
                    let x = x1 - (x1 - x2)
                    var y = 0.0
                    let width = (x1 - x2) * 2
                    var height = 0.0
                    if y1 >= y2{
                        height = (y1 - y2) * 2
                    }
                    else {
                        height = (y2 - y1) * 2
                    }
                    y = y2 - height / 2
                    let a = width / 2
                    let b = height / 2
                    chart.startMovePlot = ellipseHasPoint(ix:mp.x, iy:mp.y, oX:x + (width / 2), oY:y + (height / 2), a:a, b:b)
                }else if plot.plotType == "LRBand" {
                    chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                    if !chart.startMovePlot {
                        var list = [Double]()
                        let minIndex = min(index1, index2)
                        let maxIndex = max(index1, index2)
                        for j in minIndex...maxIndex{
                            list.append(chart.data[j].close)
                        }
                        linearRegressionEquation(chart:chart, list:list)
                        getLRBandRange(chart:chart, plot:plot, a:chart.kChart, b:chart.bChart)
                        mpy1 = getChartY(chart:chart, divIndex:0, value:plot.value1 + chart.upSubValue)
                        mpy2 = getChartY(chart:chart, divIndex:0, value:plot.value2 + chart.upSubValue)
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                        if !chart.startMovePlot {
                            mpy1 = getChartY(chart:chart, divIndex:0, value:plot.value1 - chart.downSubValue)
                            mpy2 = getChartY(chart:chart, divIndex:0, value:plot.value2 - chart.downSubValue)
                            chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                        }
                    }
                }else if plot.plotType == "LRChannel" {
                    lineXY(chart:chart, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2, oX:0, oY:0)
                    let rightX = chart.size.cx - chart.rightVScaleWidth
                    var rightY = rightX * chart.kChart + chart.bChart
                    chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:rightX, y2:rightY)
                    if !chart.startMovePlot {
                        var list = [Double]()
                        let minIndex = min(index1, index2)
                        let maxIndex = max(index1, index2)
                        for j in minIndex...maxIndex{
                            list.append(chart.data[j].close)
                        }
                        linearRegressionEquation(chart:chart, list:list)
                        getLRBandRange(chart:chart, plot:plot, a:chart.kChart, b:chart.bChart)
                        mpy1 = getChartY(chart:chart, divIndex:0, value:plot.value1 + chart.upSubValue)
                        mpy2 = getChartY(chart:chart, divIndex:0, value:plot.value2 + chart.upSubValue)
                        lineXY(chart:chart, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2, oX:0, oY:0)
                        rightY = rightX * chart.kChart + chart.bChart
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:rightX, y2:rightY)
                        if !chart.startMovePlot {
                            mpy1 = getChartY(chart:chart, divIndex:0, value:plot.value1 - chart.downSubValue)
                            mpy2 = getChartY(chart:chart, divIndex:0, value:plot.value2 - chart.downSubValue)
                            lineXY(chart:chart, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2, oX:0, oY:0)
                            rightY = rightX * chart.kChart + chart.bChart
                            chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:rightX, y2:rightY)
                        }
                    }
                }else if plot.plotType == "ParalleGram" {
                    parallelogram(chart:chart, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2, x3:mpx3, y3:mpy3)
                    chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                    if !chart.startMovePlot {
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx2, y1:mpy2, x2:mpx3, y2:mpy3)
                        if !chart.startMovePlot {
                            chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx3, y1:mpy3, x2:chart.x4Chart, y2:chart.y4Chart)
                            if !chart.startMovePlot {
                                chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:chart.x4Chart, y1:chart.y4Chart, x2:mpx1, y2:mpy1)
                            }
                        }
                    }
                }else if plot.plotType == "SpeedResist" {
                    chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                    if !chart.startMovePlot {
                        if (mpx1 != mpx2 && mpy1 != mpy2) {
                            let firstP = FCPoint(x:mpx2, y:mpy2 - (mpy2 - mpy1) / 3)
                            let secondP = FCPoint(x:mpx2, y:mpy2 - (mpy2 - mpy1) * 2 / 3)
                            let startP = FCPoint(x:mpx1, y:mpy1)
                            var fK = 0.0, fB = 0.0, sK = 0.0, sB = 0.0
                            lineXY(chart:chart, x1:startP.x, y1:startP.y, x2:firstP.x, y2:firstP.y, oX:0, oY:0)
                            fK = chart.kChart
                            fB = chart.bChart
                            lineXY(chart:chart, x1:startP.x, y1:startP.y, x2:secondP.x, y2:secondP.y, oX:0, oY:0)
                            sK = chart.kChart
                            sB = chart.bChart
                            var newYF = 0.0, newYS = 0.0
                            var newX = 0.0
                            if mpx2 > mpx1 {
                                newYF = fK * (chart.size.cx - chart.rightVScaleWidth) + fB
                                newYS = sK * (chart.size.cx - chart.rightVScaleWidth) + sB
                                newX = (chart.size.cx - chart.rightVScaleWidth)
                            }
                            else {
                                newYF = fB
                                newYS = sB
                                newX = chart.leftVScaleWidth
                            }
                            chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:startP.x, y1:startP.y, x2:newX, y2:newYF)
                            if !chart.startMovePlot {
                                chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:startP.x, y1:startP.y, x2:newX, y2:newYS)
                            }
                        }
                    }
                }else if plot.plotType == "FiboFanline" {
                    chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                    if !chart.startMovePlot {
                        if mpx1 != mpx2 && mpy1 != mpy2 {
                            let firstP = FCPoint(x:mpx2, y:mpy2 - (mpy2 - mpy1) * 0.382)
                            let secondP = FCPoint(x:mpx2, y:mpy2 - (mpy2 - mpy1) * 0.5)
                            let thirdP = FCPoint(x:mpx2, y:mpy2 - (mpy2 - mpy1) * 0.618)
                            let startP = FCPoint(x:mpx1, y:mpy1)
                            var listP = [FCPoint]()
                            listP.append(firstP)
                            listP.append(secondP)
                            listP.append(thirdP)
                            let listSize = listP.count
                            for j in 0...listSize - 1{
                                lineXY(chart:chart, x1:startP.x, y1:startP.y, x2:listP[j].x, y2:listP[j].y, oX:0, oY:0)
                                var newX = 0.0
                                var newY = 0.0
                                if mpx2 > mpx1 {
                                    newY = chart.kChart * (chart.size.cx - chart.rightVScaleWidth) + chart.bChart
                                    newX = (chart.size.cx - chart.rightVScaleWidth)
                                }
                                else {
                                    newY = chart.bChart
                                    newX = chart.leftVScaleWidth
                                }
                                chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:startP.x, y1:startP.y, x2:newX, y2:newY)
                                if chart.startMovePlot {
                                    break
                                }
                            }
                        }
                    }
                }else if plot.plotType == "FiboTimezone" {
                    var fValue = 1
                    let aIndex = index1
                    var pos = 1
                    let divHeight = getCandleDivHeight(chart:chart)
                    chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:mpx1, y1:0, x2:mpx1, y2:divHeight)
                    if !chart.startMovePlot {
                        while aIndex + fValue <= chart.lastVisibleIndex {
                            fValue = fibonacciValue(index:pos)
                            let newIndex = aIndex + fValue
                            let newX = getChartX(chart:chart, index:newIndex)
                            chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:newX, y1:0, x2:newX, y2:divHeight)
                            if chart.startMovePlot {
                                break
                            }
                            pos += 1
                        }
                    }
                }
                else if plot.plotType == "Percent" {
                    let list = getPercentParams(y1:mpy1, y2:mpy2)
                    for j in 0...list.count - 1{
                        chart.startMovePlot = selectSegment(chart:chart, mp:mp, x1:chart.leftVScaleWidth, y1:list[j], x2:chart.size.cx - chart.rightVScaleWidth, y2:list[j])
                        if chart.startMovePlot {
                            break
                        }
                    }
                }
                if chart.startMovePlot {
                    sPlot = plot
                    plot.startKey1 = plot.key1
                    plot.startValue1 = plot.value1
                    plot.startKey2 = plot.key2
                    plot.startValue2 = plot.value2
                    plot.startKey3 = plot.key3
                    plot.startValue3 = plot.value3
                    break
                }
            }
        }
    }
    return sPlot
}

/*
* 计算线性回归上下限
* chart:图表
* plot:画线
* a:直线k
* b:直线b
*/
func getLRBandRange(chart:FCChart, plot:FCPlot, a:Double, b:Double) {
    var bIndex = getChartIndexByDate(chart:chart, date:plot.key1)
    var eIndex = getChartIndexByDate(chart:chart, date:plot.key2)
    let tempBIndex = min(bIndex, eIndex)
    let tempEIndex = max(bIndex, eIndex)
    bIndex = tempBIndex
    eIndex = tempEIndex
    var upList = [Double]()
    var downList = [Double]()
    for i in bIndex...eIndex{
        let high = chart.data[i].high
        let low = chart.data[i].low
        let midValue = Double(i - bIndex + 1) * a + b
        upList.append(high - midValue)
        downList.append(midValue - low)
    }
    chart.upSubValue = maxValue(list:upList)
    chart.downSubValue = maxValue(list:downList)
}

/*
* 根据位置计算索引
* chart:图表
* mp:坐标
*/
func getChartIndex(chart:FCChart, mp:FCPoint)->Int{
    if chart.data.count == 0 {
        return -1
    }
    if mp.x <= 0 {
        return 0
    }
    var intX = Int(mp.x - chart.leftVScaleWidth - chart.hScalePixel - chart.offsetX)
    if intX < 0{
        intX = 0
    }
    var index = chart.firstVisibleIndex + Int(Double(intX) / chart.hScalePixel)
    if chart.hScalePixel > 1{
        if intX % Int(chart.hScalePixel) != 0 {
            index += 1
        }
    }
    if index < 0 {
        index = 0
    } else if index > chart.data.count - 1 {
        index = chart.data.count - 1
    }
    return index
}

/*
* 获取最大显示记录条数
* chart:图表
* hScalePixel:间隔
* pureH:横向距离
*/
func getChartMaxVisibleCount(chart:FCChart, hScalePixel:Double, pureH:Double)->Int{
    var count = Int((pureH - hScalePixel) / hScalePixel)
    if count < 0 {
        count = 0
    }
    return count
}

/*
* 获取图表层的高度
* chart:图表
*/
func getCandleDivHeight(chart:FCChart)->Double {
    let height = chart.size.cy - chart.hScaleHeight
    if height > 0 {
        return height * chart.candleDivPercent
    } else {
        return 0
    }
}

/*
* 获取成交量层的高度
* chart:图表
*/
func getVolDivHeight(chart:FCChart)->Double {
    let height = chart.size.cy - chart.hScaleHeight
    if height > 0 {
        return height * chart.volDivPercent
    } else {
        return 0
    }
}

/*
* 获取指标层的高度
* chart:图表
*/
func getIndDivHeight(chart:FCChart)->Double {
    let height = chart.size.cy - chart.hScaleHeight
    if height > 0 {
        return height * chart.indDivPercent
    } else {
        return 0
    }
}

/*
* 获取指标层2的高度
* chart:图表
*/
func getIndDivHeight2(chart:FCChart)->Double {
    let height = chart.size.cy - chart.hScaleHeight
    if height > 0 {
        return height * chart.indDivPercent2
    } else {
        return 0
    }
}

/*
* 获取横向工作区
* chart:图表
*/
func getChartWorkAreaWidth(chart:FCChart)->Double {
    return chart.size.cx - chart.leftVScaleWidth - chart.rightVScaleWidth - chart.rightSpace - chart.offsetX
}

/*
* 根据索引获取横坐标
* chart:图表
* index:索引
*/
func getChartX(chart:FCChart, index:Int)->Double {
    return chart.leftVScaleWidth + Double(index - chart.firstVisibleIndex) * chart.hScalePixel + chart.hScalePixel / 2 + chart.offsetX
}

/*
* 根据日期获取索引
* chart:图表
* date:日期
*/
func getChartIndexByDate(chart:FCChart, date:Double)->Int {
    var index = -1
    if chart.data.count > 0{
        for i in 0...chart.data.count - 1 {
            if chart.data[i].date == date {
                index = i
                break
            }
        }
    }
    return index
}

/*
* 根据索引获取日期
* chart:图表
* index:索引
*/
func getChartDateByIndex(chart:FCChart, index:Int)->Double {
    var date:Double = 0
    if chart.data.count > 0{
        if index >= 0 && index < chart.data.count {
            date = chart.data[index].date
        }
    }
    return date
}

/*
* 计算数值在层中的位置
* chart:图表
* divIndex:所在层
* chart:数值
*/
func getChartY(chart:FCChart, divIndex:Int, value:Double) ->Double {
    if divIndex == 0 {
        if chart.candleMax > chart.candleMin {
            var cValue:Double = value
            var cMax:Double = chart.candleMax
            var cMin:Double = chart.candleMin
            if chart.vScaleType != "standard" {
                if cValue > 0 {
                    cValue = log(cValue)
                } else if cValue < 0 {
                    cValue = -log(abs(cValue))
                }
                if cMax > 0 {
                    cMax = log(cMax)
                } else if cMax < 0 {
                    cMax = -log(abs(cMax))
                }
                if cMin > 0 {
                    cMin = log(cMin)
                } else if cMin < 0 {
                    cMin = -log(abs(cMin))
                }
            }
            let rate = (cValue - cMin) / (cMax - cMin)
            let divHeight = getCandleDivHeight(chart:chart)
            return divHeight - chart.candlePaddingBottom - (divHeight - chart.candlePaddingTop - chart.candlePaddingBottom) * rate
        } else {
            return 0
        }
    } else if divIndex == 1 {
        if chart.volMax > chart.volMin {
            let rate = (value - chart.volMin) / (chart.volMax - chart.volMin)
            let candleHeight = getCandleDivHeight(chart:chart)
            let volHeight = getVolDivHeight(chart:chart)
            return candleHeight + volHeight - chart.volPaddingBottom - (volHeight - chart.volPaddingTop - chart.volPaddingBottom) * rate
        } else {
            return 0
        }
    } else if divIndex == 2 {
        if chart.indMax > chart.indMin {
            let rate = (value - chart.indMin) / (chart.indMax - chart.indMin)
            let candleHeight = getCandleDivHeight(chart:chart)
            let volHeight = getVolDivHeight(chart:chart)
            let indHeight = getIndDivHeight(chart:chart)
            return candleHeight + volHeight + indHeight - chart.indPaddingBottom - (indHeight - chart.indPaddingTop - chart.indPaddingBottom) * rate
        } else {
            return 0
        }
    }
    else if divIndex == 3 {
        if chart.indMax2 > chart.indMin2 {
            let rate = (value - chart.indMin2) / (chart.indMax2 - chart.indMin2)
            let candleHeight = getCandleDivHeight(chart:chart)
            let volHeight = getVolDivHeight(chart:chart)
            let indHeight = getIndDivHeight(chart:chart)
            let indHeight2 = getIndDivHeight2(chart:chart)
            return candleHeight + volHeight + indHeight + indHeight2 - chart.indPaddingBottom2 - (indHeight2 - chart.indPaddingTop2 - chart.indPaddingBottom2) * rate
        } else {
            return 0
        }
    }
    return 0
}

/*
* 计算数值在层中的右轴位置
* chart:图表
* divIndex:所在层
* chart:数值
*/
func getChartYInRight(chart:FCChart, divIndex:Int, value:Double) ->Double {
    if divIndex == 0 {
        if chart.candleMaxRight > chart.candleMinRight {
            var cValue:Double = value
            var cMax:Double = chart.candleMaxRight
            var cMin:Double = chart.candleMinRight
            if chart.vScaleType != "standard" {
                if cValue > 0 {
                    cValue = log(cValue)
                } else if cValue < 0 {
                    cValue = -log(abs(cValue))
                }
                if cMax > 0 {
                    cMax = log(cMax)
                } else if cMax < 0 {
                    cMax = -log(abs(cMax))
                }
                if cMin > 0 {
                    cMin = log(cMin)
                } else if (cMin < 0) {
                    cMin = -log(abs(cMin))
                }
            }
            let rate = (cValue - cMin) / (cMax - cMin)
            let divHeight = getCandleDivHeight(chart:chart)
            return divHeight - chart.candlePaddingBottom - (divHeight - chart.candlePaddingTop - chart.candlePaddingBottom) * rate
        } else {
            return 0
        }
    } else if divIndex == 1 {
        if chart.volMaxRight > chart.volMinRight {
            let rate = (value - chart.volMinRight) / (chart.volMaxRight - chart.volMinRight)
            let candleHeight = getCandleDivHeight(chart:chart)
            let volHeight = getVolDivHeight(chart:chart)
            return candleHeight + volHeight - chart.volPaddingBottom - (volHeight - chart.volPaddingTop - chart.volPaddingBottom) * rate
        } else {
            return 0
        }
    } else if divIndex == 2 {
        if chart.indMaxRight > chart.indMinRight {
            let rate = (value - chart.indMinRight) / (chart.indMaxRight - chart.indMinRight)
            let candleHeight = getCandleDivHeight(chart:chart)
            let volHeight = getVolDivHeight(chart:chart)
            let indHeight = getIndDivHeight(chart:chart)
            return candleHeight + volHeight + indHeight - chart.indPaddingBottom - (indHeight - chart.indPaddingTop - chart.indPaddingBottom) * rate
        } else {
            return 0
        }
    }
    else if divIndex == 3 {
        if chart.indMax2Right > chart.indMin2Right {
            let rate = (value - chart.indMin2Right) / (chart.indMax2Right - chart.indMin2Right)
            let candleHeight = getCandleDivHeight(chart:chart)
            let volHeight = getVolDivHeight(chart:chart)
            let indHeight = getIndDivHeight(chart:chart)
            let indHeight2 = getIndDivHeight2(chart:chart)
            return candleHeight + volHeight + indHeight + indHeight2 - chart.indPaddingBottom2 - (indHeight2 - chart.indPaddingTop2 - chart.indPaddingBottom2) * rate
        } else {
            return 0
        }
    }
    return 0
}

/*
* 根据坐标获取对应的值
* chart:图表
* point:坐标
*/
func getChartValue(chart:FCChart, point:FCPoint) ->Double {
    let candleHeight = getCandleDivHeight(chart:chart)
    let volHeight = getVolDivHeight(chart:chart)
    let indHeight = getIndDivHeight(chart:chart)
    let indHeight2 = getIndDivHeight(chart:chart)
    if point.y <= candleHeight {
        if candleHeight - chart.candlePaddingTop - chart.candlePaddingBottom > 0{
            let rate = (candleHeight - chart.candlePaddingBottom - point.y) / (candleHeight - chart.candlePaddingTop - chart.candlePaddingBottom)
            var cMin:Double = chart.candleMin
            var cMax:Double = chart.candleMax
            if chart.vScaleType != "standard" {
                if cMax > 0 {
                    cMax = log(cMax)
                } else if cMax < 0 {
                    cMax = -log(abs(cMax))
                }
                if cMin > 0 {
                    cMin = log(cMin)
                } else if cMin < 0 {
                    cMin = -log(abs(cMin))
                }
            }
            let result = cMin + (cMax - cMin) * rate
            if chart.vScaleType != "standard" {
                return pow(10, result)
            } else {
                return result
            }
        }
    }
    else if point.y > candleHeight && point.y <= candleHeight + volHeight {
        if volHeight - chart.volPaddingTop - chart.volPaddingBottom > 0{
            let rate = (volHeight - chart.volPaddingBottom - (point.y - candleHeight)) / (volHeight - chart.volPaddingTop - chart.volPaddingBottom)
            return chart.volMin + (chart.volMax - chart.volMin) * rate
        }
    } else if point.y > candleHeight + volHeight && point.y <= candleHeight + volHeight + indHeight {
        if indHeight - chart.indPaddingTop - chart.indPaddingBottom > 0{
            let rate = (indHeight - chart.indPaddingBottom - (point.y - candleHeight - volHeight)) / (indHeight - chart.indPaddingTop - chart.indPaddingBottom)
            return chart.indMin + (chart.indMax - chart.indMin) * rate
        }
    } else if point.y > candleHeight + volHeight + indHeight && point.y <= candleHeight + volHeight + indHeight + indHeight2 {
        if indHeight2 - chart.indPaddingTop2 - chart.indPaddingBottom2 > 0{
            let rate = (indHeight2 - chart.indPaddingBottom2 - (point.y - candleHeight - volHeight - indHeight)) / (indHeight2 - chart.indPaddingTop2 - chart.indPaddingBottom2)
            return chart.indMin2 + (chart.indMax2 - chart.indMin2) * rate
        }
    }
    return 0
}

/*
* 根据坐标获取对应的值
* chart:图表
* point:坐标
*/
func getCandleDivValue(chart:FCChart, point:FCPoint) ->Double {
    let candleHeight = getCandleDivHeight(chart:chart)
    var rate = 0.0;
    if candleHeight - chart.candlePaddingTop - chart.candlePaddingBottom > 0{
        rate = (candleHeight - chart.candlePaddingBottom - point.y) / (candleHeight - chart.candlePaddingTop - chart.candlePaddingBottom)
    }
    var cMin:Double = chart.candleMin
    var cMax:Double = chart.candleMax
    if chart.vScaleType != "standard" {
        if cMax > 0 {
            cMax = log(cMax)
        } else if cMax < 0 {
            cMax = -log(abs(cMax))
        }
        if cMin > 0 {
            cMin = log(cMin)
        } else if cMin < 0 {
            cMin = -log(abs(cMin))
        }
    }
    let result = cMin + (cMax - cMin) * rate
    if chart.vScaleType != "standard" {
        return pow(10, result)
    } else {
        return result
    }
}

/*
* 检查最后可见索引
* chart:图表
*/
func checkChartLastVisibleIndex(chart:FCChart) {
    let dataCount = chart.data.count;
    let workingAreaWidth = getChartWorkAreaWidth(chart:chart)
    let maxVisibleRecord = getChartMaxVisibleCount(chart:chart,hScalePixel: chart.hScalePixel, pureH: workingAreaWidth)
    if chart.firstVisibleIndex < 0{
        chart.firstVisibleIndex = 0
    }
    if(chart.lastVisibleIndex >= chart.firstVisibleIndex + maxVisibleRecord - 1) || (chart.lastVisibleIndex < dataCount - 1){
        chart.lastVisibleIndex = chart.firstVisibleIndex + maxVisibleRecord - 1
    }
    if chart.lastVisibleIndex > dataCount - 1{
        chart.lastVisibleIndex = dataCount - 1
    }
    if chart.data.count > 0 && chart.lastVisibleIndex != -1 {
        chart.lastVisibleKey = chart.data[chart.lastVisibleIndex].date
        if chart.lastVisibleIndex == chart.data.count - 1 {
            chart.lastRecordIsVisible = true
        } else {
            chart.lastRecordIsVisible = false
        }
    } else {
        chart.lastVisibleKey = 0
        chart.lastRecordIsVisible = true
    }
}

/*
* 自动设置首先可见和最后可见的记录号
* chart:图表
*/
func resetChartVisibleRecord(chart:FCChart) {
    let rowsCount = chart.data.count
    let workingAreaWidth = getChartWorkAreaWidth(chart:chart)
    if chart.autoFillHScale {
        if workingAreaWidth > 0 && rowsCount > 0 {
            chart.hScalePixel = workingAreaWidth / Double(rowsCount)
            chart.firstVisibleIndex = 0
            chart.lastVisibleIndex = rowsCount - 1
        }
    } else {
        let maxVisibleRecord = getChartMaxVisibleCount(chart:chart, hScalePixel:chart.hScalePixel, pureH:workingAreaWidth)
        //没数据时重置
        if rowsCount == 0 {
            chart.firstVisibleIndex = -1
            chart.lastVisibleIndex = -1
        } else {
            //数据不足一屏时
            if rowsCount < maxVisibleRecord {
                chart.lastVisibleIndex = rowsCount - 1
                chart.firstVisibleIndex = 0
            }
            //数据超过一屏时
            else {
                //显示中间的数据时
                if chart.firstVisibleIndex != -1 && chart.lastVisibleIndex != -1 && !chart.lastRecordIsVisible {
                    let index = getChartIndexByDate(chart:chart, date:chart.lastVisibleKey)
                    if index != -1 {
                        chart.lastVisibleIndex = index
                    }
                    chart.firstVisibleIndex = chart.lastVisibleIndex - maxVisibleRecord + 1
                    if chart.firstVisibleIndex < 0 {
                        chart.firstVisibleIndex = 0
                        chart.lastVisibleIndex = chart.firstVisibleIndex + maxVisibleRecord
                        checkChartLastVisibleIndex(chart:chart)
                    }
                } else {
                    //第一条或最后一条数据被显示时
                    chart.lastVisibleIndex = rowsCount - 1
                    chart.firstVisibleIndex = chart.lastVisibleIndex - maxVisibleRecord + 1
                    if chart.firstVisibleIndex > chart.lastVisibleIndex {
                        chart.firstVisibleIndex = chart.lastVisibleIndex
                    }
                }
            }
        }
    }
}

/*
* 设置可见索引
* chart:图表
* firstVisibleIndex:起始索引
* lastVisibleIndex:结束索引
*/
func setChartVisibleIndex(chart:FCChart, firstVisibleIndex:Int, lastVisibleIndex:Int) {
    let xScalePixel = getChartWorkAreaWidth(chart:chart) / Double(lastVisibleIndex - firstVisibleIndex + 1)
    if xScalePixel < 1000000 {
        chart.firstVisibleIndex = firstVisibleIndex
        chart.lastVisibleIndex = lastVisibleIndex
        //设置最后一条记录是否可见
        if lastVisibleIndex != chart.data.count - 1 {
            chart.lastRecordIsVisible = false
        } else {
            chart.lastRecordIsVisible = true
        }
        chart.hScalePixel = xScalePixel
        checkChartLastVisibleIndex(chart:chart)
    }
}

/*
* 清除图形
* chart:图表
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawChart(chart:FCChart, paint:FCPaint, clipRect:FCRect) {
    if chart.backColor != "none" {
        paint.fillRect(color:chart.backColor, left:0, top:0, right:chart.size.cx, bottom:chart.size.cy)
    }
    if chart.hasPaintChartScaleEvent{
        chart.onPaintChartScale(chart, paint, clipRect)
    }
    else if paint.hasPaintChartScaleEvent{
        paint.onPaintChartScale(chart, paint, clipRect)
    }else{
        drawChartScale(chart:chart, paint:paint, clipRect:clipRect)
    }
    if chart.hasPaintChartStockEvent{
        chart.onPaintChartStock(chart, paint, clipRect)
    }
    else if paint.hasPaintChartStockEvent{
        paint.onPaintChartStock(chart, paint, clipRect)
    }else{
        drawChartStock(chart:chart, paint:paint, clipRect:clipRect)
    }
    if chart.hasPaintChartPlotEvent{
        chart.onPaintChartPlot(chart, paint, clipRect)
    }
    else if paint.hasPaintChartPlotEvent{
        paint.onPaintChartPlot(chart, paint, clipRect)
    }else{
        drawChartPlot(chart:chart, paint:paint, clipRect:clipRect)
    }
    if chart.hasPaintChartCrossLineEvent{
        chart.onPaintChartCrossLine(chart, paint, clipRect)
    }
    else if paint.hasPaintChartCrossLineEvent{
        paint.onPaintChartCrossLine(chart, paint, clipRect)
    }else{
        drawChartCrossLine(chart:chart, paint:paint, clipRect:clipRect)
    }
    if chart.borderColor != "none" {
        paint.drawRect(color:chart.borderColor, width:chart.lineWidthChart, style:[], left:0, top:0, right:chart.size.cx, bottom:chart.size.cy)
    }
}

/*
* 计算坐标轴
* min:最小值
* max:最大值
* yLen:长度
* maxSpan:最大间隔
* minSpan:最小间隔
* defCount:数量
*/
func chartGridScale(chart:FCChart, min:Double, max:Double, yLen:Int, maxSpan:Double, minSpan:Double, defCount:Int){
    let sub = max - min
    let nMinCount = Int(ceil(Double(yLen) / maxSpan))
    let nMaxCount = Int(floor(Double(yLen) / minSpan))
    var nCount = defCount
    var logStep = sub / Double(nCount)
    var start = false
    var divisor:Double = 0
    var i = 15, nTemp = 0
    chart.gridStepChart = 0
    chart.gridDigitChart = 0
    nCount = nMinCount > nCount ? nMinCount : nCount
    nCount = nMaxCount > nCount ? nCount : nMaxCount
    nCount = nCount > 1 ? nCount : 1
    while i >= -6 {
        divisor = pow(10.0, Double(i))
        if divisor < 1 {
            chart.gridDigitChart += 1
        }
        nTemp = Int(floor(logStep / divisor))
        if start {
            if nTemp < 4 {
                if chart.gridDigitChart > 0 {
                    chart.gridDigitChart -= 1
                }
            } else if nTemp >= 4 && nTemp <= 6 {
                nTemp = 5
                chart.gridStepChart += Double(nTemp) * divisor
            } else {
                chart.gridStepChart += 10 * divisor
                if chart.gridDigitChart > 0 {
                    chart.gridDigitChart -= 1
                }
            }
            break
        } else if nTemp > 0 {
            chart.gridStepChart = Double(nTemp) * divisor + chart.gridStepChart
            logStep -= chart.gridStepChart
            start = true
        }
        i -= 1
    }
}

/*
* 缩小
* chart:图表
*/
func zoomOutChart(chart:FCChart) {
    if !chart.autoFillHScale {
        var hScalePixel = chart.hScalePixel
        let oldX = getChartX(chart:chart, index:chart.crossStopIndex)
        if chart.showCrossLine && chart.targetOldX == 0{
            chart.targetOldX = oldX
        }
        let pureH = getChartWorkAreaWidth(chart:chart)
        var oriMax = -1, max = -1, deal = 0
        let dataCount = chart.data.count
        var findex = chart.firstVisibleIndex, lindex = chart.lastVisibleIndex
        if hScalePixel < pureH {
            oriMax = getChartMaxVisibleCount(chart:chart, hScalePixel:hScalePixel, pureH:pureH)
            if dataCount < oriMax {
                deal = 1
            }
            if hScalePixel > 3 {
                hScalePixel += 1
            } else {
                if hScalePixel == 1 {
                    hScalePixel = 2
                } else {
                    hScalePixel = hScalePixel * 1.5
                    if hScalePixel > 3 {
                        hScalePixel = Double(Int(hScalePixel))
                    }
                }
            }
            max = getChartMaxVisibleCount(chart:chart, hScalePixel:hScalePixel, pureH:pureH)
            if dataCount >= max {
                if deal == 1 {
                    lindex = dataCount - 1
                }
                findex = lindex - max + 1
                if findex < 0 {
                    findex = 0
                }
            }
        }
        chart.hScalePixel = hScalePixel
        if(chart.showCrossLine){
            var sX = chart.targetOldX
            findex = chart.crossStopIndex
            while sX >= chart.leftVScaleWidth + chart.hScalePixel / 2{
                findex = findex - 1
                chart.offsetX = sX - chart.leftVScaleWidth - chart.hScalePixel / 2
                sX = sX - chart.hScalePixel
            }
            findex = findex + 1
        }
        chart.firstVisibleIndex = findex
        chart.lastVisibleIndex = lindex
        checkChartLastVisibleIndex(chart:chart)
        if chart.hasCalculateChartMaxMinEvent{
            chart.onCalculateChartMaxMin(chart)
        }
        else if chart.getPaint().hasCalculateChartMaxMinEvent{
            chart.getPaint().onCalculateChartMaxMin(chart)
        }else{
            calculateChartMaxMin(chart:chart)
        }
    }
}

/*
* 放大
* chart:图表
*/
func zoomInChart(chart:FCChart) {
    if !chart.autoFillHScale {
        var hScalePixel = chart.hScalePixel
        let oldX = getChartX(chart:chart, index:chart.crossStopIndex)
        if chart.showCrossLine && chart.targetOldX2 == 0{
            chart.targetOldX2 = oldX
        }
        let pureH = getChartWorkAreaWidth(chart:chart)
        var max = -1
        let dataCount = chart.data.count
        var findex = chart.firstVisibleIndex, lindex = chart.lastVisibleIndex
        if hScalePixel > 3 {
            hScalePixel -= 1
        } else {
            hScalePixel = hScalePixel * 2 / 3
            if hScalePixel > 3 {
                hScalePixel = Double(Int(hScalePixel))
            }
        }
        max = getChartMaxVisibleCount(chart:chart, hScalePixel:hScalePixel, pureH:pureH)
        if max >= dataCount {
            if hScalePixel < 1 {
                hScalePixel = pureH / Double(max)
            }
            findex = 0
            lindex = dataCount - 1
        } else {
            findex = lindex - max + 1
            if findex < 0 {
                findex = 0
            }
        }
        chart.hScalePixel = hScalePixel
        if(chart.showCrossLine){
            var sX = chart.targetOldX2
            findex = chart.crossStopIndex
            while sX >= chart.leftVScaleWidth + chart.hScalePixel / 2{
                findex = findex - 1
                chart.offsetX = sX - chart.leftVScaleWidth - chart.hScalePixel / 2
                sX = sX - chart.hScalePixel
            }
            findex = findex + 1
        }
        chart.firstVisibleIndex = findex
        chart.lastVisibleIndex = lindex
        checkChartLastVisibleIndex(chart:chart)
        if chart.hasCalculateChartMaxMinEvent{
            chart.onCalculateChartMaxMin(chart)
        }
        else if chart.getPaint().hasCalculateChartMaxMinEvent{
            chart.getPaint().onCalculateChartMaxMin(chart)
        }else{
            calculateChartMaxMin(chart:chart)
        }
    }
}

/*
* 绘制刻度
* chart:图表
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawChartScale(chart:FCChart, paint:FCPaint, clipRect:FCRect) {
    if chart.leftVScaleWidth > 0 {
        paint.drawLine(color:chart.scaleColor, width:chart.lineWidthChart, style:[], x1:chart.leftVScaleWidth, y1:0, x2:chart.leftVScaleWidth, y2:chart.size.cy - chart.hScaleHeight)
    }
    if chart.rightVScaleWidth > 0 {
        paint.drawLine(color:chart.scaleColor, width:chart.lineWidthChart, style:[], x1:chart.size.cx - chart.rightVScaleWidth, y1:0, x2:chart.size.cx - chart.rightVScaleWidth, y2:chart.size.cy - chart.hScaleHeight)
    }
    if chart.hScaleHeight > 0 {
        paint.drawLine(color:chart.scaleColor, width:chart.lineWidthChart, style:[], x1:0, y1:chart.size.cy - chart.hScaleHeight, x2:chart.size.cx, y2:chart.size.cy - chart.hScaleHeight)
    }
    let candleDivHeight = getCandleDivHeight(chart:chart)
    let volDivHeight = getVolDivHeight(chart:chart)
    let indDivHeight = getIndDivHeight(chart:chart)
    let indDivHeight2 = getIndDivHeight2(chart:chart)
    if volDivHeight > 0 {
        paint.drawLine(color:chart.scaleColor, width:chart.lineWidthChart, style:[], x1:chart.leftVScaleWidth, y1:candleDivHeight, x2:chart.size.cx - chart.rightVScaleWidth, y2:candleDivHeight)
    }
    if indDivHeight > 0 {
        paint.drawLine(color:chart.scaleColor, width:chart.lineWidthChart, style:[], x1:chart.leftVScaleWidth, y1:candleDivHeight + volDivHeight, x2:chart.size.cx - chart.rightVScaleWidth, y2:candleDivHeight + volDivHeight)
    }
    if indDivHeight2 > 0 {
        paint.drawLine(color:chart.scaleColor, width:chart.lineWidthChart, style:[], x1:chart.leftVScaleWidth, y1:candleDivHeight + volDivHeight + indDivHeight, x2:chart.size.cx - chart.rightVScaleWidth, y2:candleDivHeight + volDivHeight + indDivHeight)
    }
    if chart.data.count == 0{
        return
    }
    var topPoint = FCPoint(x:0, y:20)
    var bottomPoint = FCPoint(x:0, y:candleDivHeight - 10)
    let candleMax = getChartValue(chart:chart, point:topPoint)
    let candleMin = getChartValue(chart:chart, point:bottomPoint)
    chartGridScale(chart:chart, min:candleMin, max:candleMax, yLen:Int((candleDivHeight - chart.candlePaddingTop - chart.candlePaddingBottom) / 2), maxSpan:chart.vScaleDistance, minSpan:chart.vScaleDistance / 2, defCount:Int((candleDivHeight - chart.candlePaddingTop - chart.candlePaddingBottom) / chart.vScaleDistance))
    if chart.gridStepChart > 0 {
        var drawValues = [Double]()
        let isTrend = chart.cycle == "trend"
        var firstOpen = chart.firstOpen
        if isTrend {
            if firstOpen == 0{
                firstOpen = chart.data[chart.firstVisibleIndex].close
            }
            var subValue = (candleMax - candleMin)
            let count = Int((candleDivHeight - chart.candlePaddingTop - chart.candlePaddingBottom) / chart.vScaleDistance)
            if count > 0 {
                subValue /= Double(count)
            }
            var start = firstOpen
            while start < candleMax {
                start += subValue
                if start <= candleMax {
                    drawValues.append(start)
                }
            }
            start = firstOpen
            while start > candleMin {
                start -= subValue
                if start >= candleMin {
                    drawValues.append(start)
                }
            }
        } else {
            var start = 0.0
            if candleMin >= 0 {
                while start + chart.gridStepChart < candleMin {
                    start += chart.gridStepChart
                }
            } else {
                while start - chart.gridStepChart > candleMin {
                    start -= chart.gridStepChart
                }
            }

            while start <= candleMax {
                if start > candleMin {
                    drawValues.append(start)
                }
                start += chart.gridStepChart
            }
        }
        drawValues.append(firstOpen)
        for i in 0...drawValues.count - 1{
            let start = drawValues[i]
            let hAxisY = getChartY(chart:chart, divIndex:0, value:start)
            if hAxisY < 1 || hAxisY > candleDivHeight {
                continue
            }
            paint.drawLine(color:chart.gridColor, width:chart.lineWidthChart, style:[], x1:chart.leftVScaleWidth, y1:hAxisY, x2:chart.size.cx - chart.rightVScaleWidth, y2:hAxisY)
            paint.drawLine(color:chart.scaleColor, width:chart.lineWidthChart, style:[], x1:chart.leftVScaleWidth - 8, y1:hAxisY, x2:chart.leftVScaleWidth, y2:hAxisY)
            paint.drawLine(color:chart.scaleColor, width:chart.lineWidthChart, style:[], x1:chart.size.cx - chart.rightVScaleWidth, y1:hAxisY, x2:chart.size.cx - chart.rightVScaleWidth + 8, y2:hAxisY)
            
            let drawText = toFixed(value:start, digit:chart.candleDigit)
            let tSize = paint.textSize(text:drawText, font:chart.font)
            if isTrend {
                let diffRange = ((start - firstOpen) / firstOpen * 100)
                let diffRangeStr = toFixed(value:diffRange, digit:2) + "%"
                if diffRange >= 0 {
                    paint.drawText(text:diffRangeStr, color:chart.upColor, font:chart.font, x:chart.size.cx - chart.rightVScaleWidth + 10, y:hAxisY - tSize.cy / 2)
                } else {
                    paint.drawText(text:diffRangeStr, color:chart.downColor, font:chart.font, x:chart.size.cx - chart.rightVScaleWidth + 10, y:hAxisY - tSize.cy / 2)
                }
            } else {
                paint.drawText(text:drawText, color:chart.textColor, font:chart.font, x:chart.size.cx - chart.rightVScaleWidth + 10, y:hAxisY - tSize.cy / 2)
            }
            paint.drawText(text:drawText, color:chart.textColor, font:chart.font, x:chart.leftVScaleWidth - tSize.cx - 10, y:hAxisY - tSize.cy / 2)
        }
        topPoint = FCPoint(x:0, y:candleDivHeight + 10)
        bottomPoint = FCPoint(x:0, y:candleDivHeight + volDivHeight - 10)
        let volMax = getChartValue(chart:chart, point:topPoint)
        let volMin = getChartValue(chart:chart, point:bottomPoint)
        chartGridScale(chart:chart, min:volMin, max:volMax, yLen:Int((volDivHeight - chart.volPaddingTop - chart.volPaddingBottom) / 2), maxSpan:chart.vScaleDistance, minSpan:chart.vScaleDistance / 2, defCount:Int((volDivHeight - chart.volPaddingTop - chart.volPaddingBottom) / chart.vScaleDistance))
        if chart.gridStepChart > 0 {
            var start = 0.0
            if volMin >= 0 {
                while start + chart.gridStepChart < volMin {
                    start += chart.gridStepChart
                }
            } else {
                while start - chart.gridStepChart > volMin {
                    start -= chart.gridStepChart
                }
            }
            while start <= volMax {
                if start > volMin {
                    let hAxisY = getChartY(chart:chart, divIndex:1, value:start)
                    if hAxisY < candleDivHeight || hAxisY > candleDivHeight + volDivHeight {
                        start += chart.gridStepChart
                        continue
                    }
                    paint.drawLine(color:chart.gridColor, width:chart.lineWidthChart, style:[], x1:chart.leftVScaleWidth, y1:hAxisY, x2:chart.size.cx - chart.rightVScaleWidth, y2:hAxisY)
                    paint.drawLine(color:chart.scaleColor, width:chart.lineWidthChart, style:[], x1:chart.leftVScaleWidth - 8, y1:hAxisY, x2:chart.leftVScaleWidth, y2:hAxisY)
                    paint.drawLine(color:chart.scaleColor, width:chart.lineWidthChart, style:[], x1:chart.size.cx - chart.rightVScaleWidth, y1:hAxisY, x2:chart.size.cx - chart.rightVScaleWidth + 8, y2:hAxisY)
                    let drawText = toFixed(value:(start / Double(chart.magnitude)), digit:chart.volDigit)
                    let tSize = paint.textSize(text:drawText, font:chart.font)
                    paint.drawText(text:drawText, color:chart.textColor, font:chart.font, x:chart.size.cx - chart.rightVScaleWidth + 10, y:hAxisY - tSize.cy / 2)
                    paint.drawText(text:drawText, color:chart.textColor, font:chart.font, x:chart.leftVScaleWidth - tSize.cx - 10, y:hAxisY - tSize.cy / 2)
                }
                start += chart.gridStepChart
            }
        }
    }
    if indDivHeight > 0 {
        topPoint = FCPoint(x:0, y:candleDivHeight + volDivHeight + 10)
        bottomPoint = FCPoint(x:0, y:candleDivHeight + volDivHeight + indDivHeight - 10)
        let indMax = getChartValue(chart:chart, point:topPoint)
        let indMin = getChartValue(chart:chart, point:bottomPoint)
        chartGridScale(chart:chart, min:indMin, max:indMax, yLen:Int((indDivHeight - chart.indPaddingTop - chart.indPaddingBottom) / 2), maxSpan:chart.vScaleDistance, minSpan:chart.vScaleDistance / 2, defCount:Int((indDivHeight - chart.indPaddingTop - chart.indPaddingBottom) / chart.vScaleDistance))
        if chart.gridStepChart > 0 {
            var start = 0.0
            if indMin >= 0 {
                while start + chart.gridStepChart < indMin {
                    start += chart.gridStepChart
                }
            } else {
                while start - chart.gridStepChart > indMin {
                    start -= chart.gridStepChart
                }
            }

            while start <= indMax {
                if start > indMin {
                    let hAxisY = getChartY(chart:chart, divIndex:2, value:start)
                    if hAxisY < candleDivHeight + volDivHeight || hAxisY > candleDivHeight + volDivHeight + indDivHeight {
                        start += chart.gridStepChart
                        continue
                    }
                    paint.drawLine(color:chart.gridColor, width:chart.lineWidthChart, style:[], x1:chart.leftVScaleWidth, y1:hAxisY, x2:chart.size.cx - chart.rightVScaleWidth, y2:hAxisY)
                    paint.drawLine(color:chart.scaleColor, width:chart.lineWidthChart, style:[], x1:chart.leftVScaleWidth - 8, y1:hAxisY, x2:chart.leftVScaleWidth, y2:hAxisY)
                    paint.drawLine(color:chart.scaleColor, width:chart.lineWidthChart, style:[], x1:chart.size.cx - chart.rightVScaleWidth, y1:hAxisY, x2:chart.size.cx - chart.rightVScaleWidth + 8, y2:hAxisY)
                    let drawText = toFixed(value:start, digit:chart.indDigit)
                    let tSize = paint.textSize(text:drawText, font:chart.font)
                    paint.drawText(text:drawText, color:chart.textColor, font:chart.font, x:chart.size.cx - chart.rightVScaleWidth + 10, y:hAxisY - tSize.cy / 2)
                    paint.drawText(text:drawText, color:chart.textColor, font:chart.font, x:chart.leftVScaleWidth - tSize.cx - 10, y:hAxisY - tSize.cy / 2)
                }
                start += chart.gridStepChart
            }
        }
    }
    if indDivHeight2 > 0 {
        topPoint = FCPoint(x:0, y:candleDivHeight + volDivHeight + indDivHeight + 10)
        bottomPoint = FCPoint(x:0, y:candleDivHeight + volDivHeight + indDivHeight + indDivHeight2 - 10)
        let indMax2 = getChartValue(chart:chart, point:topPoint)
        let indMin2 = getChartValue(chart:chart, point:bottomPoint)
        chartGridScale(chart:chart, min:indMin2, max:indMax2, yLen:Int((indDivHeight2 - chart.indPaddingTop2 - chart.indPaddingBottom2) / 2), maxSpan:chart.vScaleDistance, minSpan:chart.vScaleDistance / 2, defCount:Int((indDivHeight2 - chart.indPaddingTop2 - chart.indPaddingBottom2) / chart.vScaleDistance))
        if chart.gridStepChart > 0 {
            var start = 0.0
            if indMin2 >= 0 {
                while start + chart.gridStepChart < indMin2 {
                    start += chart.gridStepChart
                }
            } else {
                while start - chart.gridStepChart > indMin2 {
                    start -= chart.gridStepChart
                }
            }

            while start <= indMax2 {
                if start > indMin2 {
                    let hAxisY = getChartY(chart:chart, divIndex:3, value:start)
                    if hAxisY < candleDivHeight + volDivHeight + indDivHeight || hAxisY > candleDivHeight + volDivHeight + indDivHeight + indDivHeight2 {
                        start += chart.gridStepChart
                        continue
                    }
                    paint.drawLine(color:chart.gridColor, width:chart.lineWidthChart, style:[], x1:chart.leftVScaleWidth, y1:hAxisY, x2:chart.size.cx - chart.rightVScaleWidth, y2:hAxisY)
                    paint.drawLine(color:chart.scaleColor, width:chart.lineWidthChart, style:[], x1:chart.leftVScaleWidth - 8, y1:hAxisY, x2:chart.leftVScaleWidth, y2:hAxisY)
                    paint.drawLine(color:chart.scaleColor, width:chart.lineWidthChart, style:[], x1:chart.size.cx - chart.rightVScaleWidth, y1:hAxisY, x2:chart.size.cx - chart.rightVScaleWidth + 8, y2:hAxisY)
                    let drawText = toFixed(value:start, digit:chart.indDigit)
                    let tSize = paint.textSize(text:drawText, font:chart.font)
                    paint.drawText(text:drawText, color:chart.textColor, font:chart.font, x:chart.size.cx - chart.rightVScaleWidth + 10, y:hAxisY - tSize.cy / 2)
                    paint.drawText(text:drawText, color:chart.textColor, font:chart.font, x:chart.leftVScaleWidth - tSize.cx - 10, y:hAxisY - tSize.cy / 2)
                }
                start += chart.gridStepChart
            }
        }
    }
    if chart.hasPaintChartHScaleEvent{
        chart.onPaintChartHScale(chart, paint, clipRect)
    }
    else if paint.hasPaintChartHScaleEvent{
        paint.onPaintChartHScale(chart, paint, clipRect)
    }else{
        if chart.data.count > 0 && chart.hScaleHeight > 0 {
            let dLeft = chart.leftVScaleWidth + 10
            var i = chart.firstVisibleIndex
            while i <= chart.lastVisibleIndex{
                var xText = ""
                let timeInterval:TimeInterval = TimeInterval(chart.data[i].date)
                let date = Date(timeIntervalSince1970: timeInterval)
                let dateformatter = DateFormatter()
                if chart.hScaleFormat.count > 0 {
                    dateformatter.dateFormat = chart.hScaleFormat
                    xText =  dateformatter.string(from:date)
                } else {
                    if chart.cycle == "day" {
                        dateformatter.dateFormat = "YYYY-mm-dd"
                        xText =  dateformatter.string(from:date)
                    } else if chart.cycle == "minute" {
                        dateformatter.dateFormat = "YYYY-mm-dd HH:MM"
                        xText =  dateformatter.string(from:date)
                    } else if chart.cycle == "trend" {
                        dateformatter.dateFormat = "HH:MM"
                        xText =  dateformatter.string(from:date)
                    }else if chart.cycle == "second" {
                        dateformatter.dateFormat = "HH:MM:SS"
                        xText = dateformatter.string(from:date)
                    }else if chart.cycle == "tick" {
                        xText = String(i + 1)
                    }
                }
                let tSize = paint.textSize(text:xText, font:chart.font)
                let x = getChartX(chart:chart, index:i)
                let dx = x - tSize.cx / 2
                if dx > dLeft && dx < chart.size.cx - chart.rightVScaleWidth - 10 {
                    paint.drawLine(color:chart.scaleColor, width:chart.lineWidthChart, style:[], x1:x, y1:chart.size.cy - chart.hScaleHeight, x2:x, y2:chart.size.cy - chart.hScaleHeight + 8)
                    paint.drawText(text:xText, color:chart.textColor, font:chart.font, x:dx, y:chart.size.cy - chart.hScaleHeight + 8  - tSize.cy / 2 + 7)
                    i = i + Int((tSize.cx + chart.hScaleTextDistance) / chart.hScalePixel) + 1
                }else{
                    i = i + 1
                }
            }
        }
    }
}

/*
* 绘制十字线
* chart:图表
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawChartCrossLine(chart:FCChart, paint:FCPaint, clipRect:FCRect) {
    if chart.data.count == 0 {
        return
    }
    let candleDivHeight = getCandleDivHeight(chart:chart)
    let volDivHeight = getVolDivHeight(chart:chart)
    let indDivHeight = getIndDivHeight(chart:chart)
    let indDivHeight2 = getIndDivHeight2(chart:chart)
    var crossLineIndex = chart.crossStopIndex
    if crossLineIndex == -1 || !chart.showCrossLine{
        if chart.lastValidIndex != -1{
            crossLineIndex = chart.lastValidIndex
        }else{
            crossLineIndex = chart.lastVisibleIndex
        }
    }
    if crossLineIndex == -1{
        return
    }
    if volDivHeight > 0 {
        var drawTitles = [String]()
        var drawColors = [String]()
        drawTitles.append("VOL " + toFixed(value:chart.data[crossLineIndex].volume / Double(chart.magnitude), digit:chart.volDigit))
        drawColors.append(chart.textColor)
        if chart.shapes.count  > 0 {
            for i in 0...chart.shapes.count - 1{
                let shape = chart.shapes[i]
                if shape.divIndex == 1 {
                    if shape.title.count > 0 {
                        if shape.shapeType == "bar" && shape.style == "2color"{
                            drawTitles.append(shape.title + " " + toFixed(value:shape.datas[crossLineIndex], digit:chart.volDigit))
                            drawColors.append(shape.color2)
                        } else {
                            if shape.shapeType != "text" {
                                drawTitles.append(shape.title + " " + toFixed(value:shape.datas[crossLineIndex], digit:chart.volDigit))
                                drawColors.append(shape.color)
                                if shape.datas2.count > 0 {
                                    drawTitles.append(shape.title2 + " " + toFixed(value:shape.datas2[crossLineIndex], digit:chart.volDigit))
                                    drawColors.append(shape.color2)
                                }
                            }
                        }
                    }
                }
            }
        }
        var iLeft = chart.leftVScaleWidth + 5
        for i in 0...drawTitles.count - 1{
            let tSize = paint.textSize(text:drawTitles[i], font:chart.font)
            paint.drawText(text:drawTitles[i], color:drawColors[i], font:chart.font, x:iLeft, y:candleDivHeight + 5)
            iLeft += tSize.cx + 5
        }
    }
    //上面显示数据  高开低收
    if chart.cycle == "trend" {
        var drawTitles = [String]()
        var drawColors = [String]()
        if chart.text.count > 0{
            drawTitles.append(chart.text)
            drawColors.append(chart.textColor)
        }
        drawTitles.append("CLOSE " + toFixed(value:chart.data[crossLineIndex].close, digit:chart.candleDigit))
        drawColors.append(chart.textColor)
        if chart.shapes.count > 0 {
            for i in 0...chart.shapes.count - 1{
                let shape = chart.shapes[i]
                if shape.divIndex == 0 {
                    if shape.title.count > 0 {
                        if shape.shapeType == "bar" && shape.style == "2color" {
                            drawTitles.append(shape.title + " " + toFixed(value:shape.datas[crossLineIndex], digit:chart.candleDigit))
                            drawColors.append(shape.color2)
                        } else {
                            if shape.shapeType != "text" {
                                drawTitles.append(shape.title + " " + toFixed(value:shape.datas[crossLineIndex], digit:chart.candleDigit))
                                drawColors.append(shape.color)
                                if shape.datas2.count > 0 {
                                    drawTitles.append(shape.title2 + " " + toFixed(value:shape.datas2[crossLineIndex], digit:chart.candleDigit))
                                    drawColors.append(shape.color2)
                                }
                            }
                        }
                    }
                }
            }
        }
        var iLeft = chart.leftVScaleWidth + 5
        for i in 0...drawTitles.count - 1{
            let tSize = paint.textSize(text:drawTitles[i], font:chart.font)
            paint.drawText(text:drawTitles[i], color:drawColors[i], font:chart.font, x:iLeft, y:5)
            iLeft += tSize.cx + 5
        }
    } else {
        var drawTitles = [String]()
        var drawColors = [String]()
        if chart.text.count > 0{
            drawTitles.append(chart.text)
            drawColors.append(chart.textColor)
        }
        if chart.mainIndicator == "MA" {
            if chart.ma5.count > 0 {
                drawTitles.append("MA5 " + toFixed(value:chart.ma5[crossLineIndex], digit:chart.candleDigit))
            } else {
                drawTitles.append("MA5")
            }
            drawColors.append(chart.indicatorColors[0])
            if chart.ma10.count > 0 {
                drawTitles.append("MA10 " + toFixed(value:chart.ma10[crossLineIndex], digit:chart.candleDigit))
            } else {
                drawTitles.append("MA10")
            }
            drawColors.append(chart.indicatorColors[1])
            if chart.ma20.count > 0 {
                drawTitles.append("MA20 " + toFixed(value:chart.ma20[crossLineIndex], digit:chart.candleDigit))

            } else {
                drawTitles.append("MA20")
            }
            drawColors.append(chart.indicatorColors[2])
            if chart.ma30.count > 0 {
                drawTitles.append("MA30 " + toFixed(value:chart.ma30[crossLineIndex], digit:chart.candleDigit))
            } else {
                drawTitles.append("MA30")
            }
            drawColors.append(chart.indicatorColors[5])
            if chart.ma120.count > 0 {
                drawTitles.append("MA120 " + toFixed(value:chart.ma120[crossLineIndex], digit:chart.candleDigit))

            } else {
                drawTitles.append("MA120")
            }
            drawColors.append(chart.indicatorColors[4])
            if chart.ma250.count > 0 {
                drawTitles.append("MA250 " + toFixed(value:chart.ma250[crossLineIndex], digit:chart.candleDigit))
            } else {
                drawTitles.append("MA250")
            }
            drawColors.append(chart.indicatorColors[3])
        } else if chart.mainIndicator == "BOLL" {
            if chart.bollMid.count > 0 {
                drawTitles.append("MID " + toFixed(value:chart.bollMid[crossLineIndex], digit:chart.candleDigit))
            } else {
                drawTitles.append("MID")
            }
            drawColors.append(chart.indicatorColors[0])
            if chart.bollUp.count > 0 {
                drawTitles.append("UP " + toFixed(value:chart.bollUp[crossLineIndex], digit:chart.candleDigit))
            } else {
                drawTitles.append("UP")
            }
            drawColors.append(chart.indicatorColors[1])
            if chart.bollDown.count > 0 {
                drawTitles.append("LOW " + toFixed(value:chart.bollDown[crossLineIndex], digit:chart.candleDigit))
            } else {
                drawTitles.append("LOW")
            }
            drawColors.append(chart.indicatorColors[2])
        }
        if chart.shapes.count > 0 {
            for i in 0...chart.shapes.count - 1{
                let shape = chart.shapes[i]
                if shape.divIndex == 0 {
                    if shape.title.count > 0 {
                        if shape.shapeType == "bar" && shape.style == "2color" {
                            drawTitles.append(shape.title + " " + toFixed(value:shape.datas[crossLineIndex], digit:chart.candleDigit))
                            drawColors.append(shape.color2)
                        } else {
                            if shape.shapeType != "text" {
                                drawTitles.append(shape.title + " " + toFixed(value:shape.datas[crossLineIndex], digit:chart.candleDigit))
                                drawColors.append(shape.color)
                                if shape.datas2.count > 0 {
                                    drawTitles.append(shape.title2 + " " + toFixed(value:shape.datas2[crossLineIndex], digit:chart.candleDigit))
                                    drawColors.append(shape.color2)
                                }
                            }
                        }
                    }
                }
            }
        }
        var iLeft = chart.leftVScaleWidth + 5
        for i in 0...drawTitles.count - 1{
            let tSize = paint.textSize(text:drawTitles[i], font:chart.font)
            paint.drawText(text:drawTitles[i], color:drawColors[i], font:chart.font, x:iLeft, y:5)
            iLeft += tSize.cx + 5
        }
    }
    if indDivHeight > 0 {
        var drawTitles = [String]()
        var drawColors = [String]()
        if chart.showIndicator == "MACD" {
            if chart.alldifarr.count > 0 {
                drawTitles.append("DIF " + toFixed(value:chart.alldifarr[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("DIF")
            }
            drawColors.append(chart.indicatorColors[0])
            if chart.alldeaarr.count > 0 {
                drawTitles.append("DEA " + toFixed(value:chart.alldeaarr[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("DEA")
            }
            drawColors.append(chart.indicatorColors[1])
            if chart.allmacdarr.count > 0 {
                drawTitles.append("MACD " + toFixed(value:chart.allmacdarr[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("MACD")
            }
            drawColors.append(chart.indicatorColors[4])
        } else if chart.showIndicator == "KDJ" {
            if chart.kdjK.count > 0 {
                drawTitles.append("K " + toFixed(value:chart.kdjK[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("K")
            }
            drawColors.append(chart.indicatorColors[0])
            if chart.kdjD.count > 0 {
                drawTitles.append("D " + toFixed(value:chart.kdjD[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("D")
            }
            drawColors.append(chart.indicatorColors[1])
            if chart.kdjJ.count > 0 {
                drawTitles.append("J " + toFixed(value:chart.kdjJ[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("J")
            }
            drawColors.append(chart.indicatorColors[2])
        } else if chart.showIndicator == "RSI" {
            if chart.rsi1.count > 0 {
                drawTitles.append("RSI6 " + toFixed(value:chart.rsi1[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("RSI6")
            }
            drawColors.append(chart.indicatorColors[5])
            if chart.rsi2.count > 0 {
                drawTitles.append("RSI12 " + toFixed(value:chart.rsi2[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("RSI12")
            }
            drawColors.append(chart.indicatorColors[1])
            if chart.rsi3.count > 0 {
                drawTitles.append("RSI24 " + toFixed(value:chart.rsi3[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("RSI24")
            }
            drawColors.append(chart.indicatorColors[2])
        }
        else if chart.showIndicator == "BIAS" {
            if chart.bias1.count > 0 {
                drawTitles.append("BIAS6 " + toFixed(value:chart.bias1[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("BIAS6")
            }
            drawColors.append(chart.indicatorColors[5])
            if chart.bias2.count > 0 {
                drawTitles.append("BIAS12 " + toFixed(value:chart.bias2[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("BIAS12")
            }
            drawColors.append(chart.indicatorColors[1])
            if chart.bias3.count > 0 {
                drawTitles.append("BIAS24 " + toFixed(value:chart.bias3[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("BIAS24")
            }
            drawColors.append(chart.indicatorColors[2])
        }
        else if chart.showIndicator == "ROC" {
            if chart.roc.count > 0 {
                drawTitles.append("ROC " + toFixed(value:chart.roc[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("ROC")
            }
            drawColors.append(chart.indicatorColors[0])
            if chart.rocMa.count > 0 {
                drawTitles.append("ROCMA " + toFixed(value:chart.rocMa[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("ROCMA")
            }
            drawColors.append(chart.indicatorColors[1])
        }
        else if chart.showIndicator == "WR" {
            if (chart.wr1.count > 0) {
                drawTitles.append("WR5 " + toFixed(value:chart.wr1[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("WR5")
            }
            drawColors.append(chart.indicatorColors[0])
            if chart.wr2.count > 0 {
                drawTitles.append("WR10 " + toFixed(value:chart.wr2[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("WR10")
            }
            drawColors.append(chart.indicatorColors[1])
        }
        else if chart.showIndicator == "CCI" {
            if chart.cci.count > 0 {
                drawTitles.append("CCI " + toFixed(value:chart.cci[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("CCI")
            }
            drawColors.append(chart.indicatorColors[0])
        } else if chart.showIndicator == "BBI" {
            if chart.bbi.count > 0 {
                drawTitles.append("BBI " + toFixed(value:chart.bbi[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("BBI")
            }
            drawColors.append(chart.indicatorColors[0])
        } else if chart.showIndicator == "TRIX" {
            if chart.trix.count > 0 {
                drawTitles.append("TRIX " + toFixed(value:chart.trix[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("TRIX")
            }
            drawColors.append(chart.indicatorColors[0])
            if chart.trixMa.count > 0 {
                drawTitles.append("TRIXMA " + toFixed(value:chart.trixMa[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("TRIXMA")
            }
            drawColors.append(chart.indicatorColors[1])
        }
        else if chart.showIndicator == "DMA" {
            if chart.dma1.count > 0 {
                drawTitles.append("MA10 " + toFixed(value:chart.dma1[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("MA10")
            }
            drawColors.append(chart.indicatorColors[0])
            if chart.dma2.count > 0 {
                drawTitles.append("MA50 " + toFixed(value:chart.dma2[crossLineIndex], digit:chart.indDigit))
            } else {
                drawTitles.append("MA50")
            }
            drawColors.append(chart.indicatorColors[1])
        }
        if chart.shapes.count > 0 {
            for i in 0...chart.shapes.count - 1{
                let shape = chart.shapes[i]
                if shape.divIndex == 2 {
                    if shape.title.count > 0 {
                        if shape.shapeType == "bar" && shape.style == "2color" {
                            drawTitles.append(shape.title + " " + toFixed(value:shape.datas[crossLineIndex], digit:chart.indDigit))
                            drawColors.append(shape.color2)
                        } else {
                            if shape.shapeType != "text" {
                                drawTitles.append(shape.title + " " + toFixed(value:shape.datas[crossLineIndex], digit:chart.indDigit))
                                drawColors.append(shape.color)
                                if shape.datas2.count > 0 {
                                    drawTitles.append(shape.title2 + " " + toFixed(value:shape.datas2[crossLineIndex], digit:chart.indDigit))
                                    drawColors.append(shape.color2)
                                }
                            }
                        }
                    }
                }
            }
        }
        var iLeft = chart.leftVScaleWidth + 5
        for i in 0...drawTitles.count - 1{
            let tSize = paint.textSize(text:drawTitles[i], font:chart.font)
            paint.drawText(text:drawTitles[i], color:drawColors[i], font:chart.font,x:iLeft, y:candleDivHeight + volDivHeight + 5)
            iLeft += tSize.cx + 5
        }
    }
    if indDivHeight2 > 0 {
        var drawTitles = [String]()
        var drawColors = [String]()
        if chart.shapes.count > 0 {
            for i in 0...chart.shapes.count - 1{
                let shape = chart.shapes[i]
                if shape.divIndex == 3 {
                    if shape.title.count > 0 {
                        if shape.shapeType == "bar" && shape.style == "2color" {
                            drawTitles.append(shape.title + " " + toFixed(value:shape.datas[crossLineIndex], digit:chart.indDigit2))
                            drawColors.append(shape.color2)
                        } else {
                            if shape.shapeType != "text" {
                                drawTitles.append(shape.title + " " + toFixed(value:shape.datas[crossLineIndex], digit:chart.indDigit2))
                                drawColors.append(shape.color)
                                if shape.datas2.count > 0{
                                    drawTitles.append(shape.title2 + " " + toFixed(value:shape.datas2[crossLineIndex], digit:chart.indDigit2))
                                    drawColors.append(shape.color2)
                                }
                            }
                        }
                    }
                }
            }
        }
        if drawTitles.count > 0 {
            var iLeft = chart.leftVScaleWidth + 5
            for i in 0...drawTitles.count - 1{
                let tSize = paint.textSize(text:drawTitles[i], font:chart.font)
                paint.drawText(text:drawTitles[i], color:drawColors[i], font:chart.font, x:iLeft, y:candleDivHeight + volDivHeight + indDivHeight + 5 + tSize.cy / 2)
                iLeft += tSize.cx + 5
            }
        }
    }

    if chart.showCrossLine {
        var rightText = ""
        if chart.touchPosition.y < candleDivHeight {
            rightText = toFixed(value:getChartValue(chart:chart, point:chart.touchPosition), digit:chart.candleDigit)
        }
        else if chart.touchPosition.y > candleDivHeight && chart.touchPosition.y < candleDivHeight + volDivHeight {
            rightText = toFixed(value:getChartValue(chart:chart, point:chart.touchPosition) / Double(chart.magnitude), digit:chart.volDigit)
        } else if chart.touchPosition.y > candleDivHeight + volDivHeight && chart.touchPosition.y < candleDivHeight + volDivHeight + indDivHeight {
            rightText = toFixed(value:getChartValue(chart:chart, point:chart.touchPosition), digit:chart.indDigit)
        } else if chart.touchPosition.y > candleDivHeight + volDivHeight + indDivHeight && chart.touchPosition.y < candleDivHeight + volDivHeight + indDivHeight + indDivHeight2 {
            rightText = toFixed(value:getChartValue(chart:chart, point:chart.touchPosition), digit:chart.indDigit2)
        }

        var drawY = chart.touchPosition.y
        if drawY > chart.size.cy - chart.hScaleHeight {
            drawY = chart.size.cy - chart.hScaleHeight
        }
        let tSize = paint.textSize(text:rightText, font:chart.font)
        if chart.leftVScaleWidth > 0 {
            paint.fillRect(color:chart.crossTipColor, left:chart.leftVScaleWidth - tSize.cx, top:drawY - tSize.cy / 2 - 4, right:chart.leftVScaleWidth, bottom:drawY + tSize.cy / 2 + 3)
            paint.drawText(text:rightText, color:chart.textColor, font:chart.font, x:chart.leftVScaleWidth - tSize.cx, y:drawY - tSize.cy / 2)
        }
        if chart.rightVScaleWidth > 0 {
            paint.fillRect(color:chart.crossTipColor, left:chart.size.cx - chart.rightVScaleWidth, top:drawY - tSize.cy / 2 - 4, right:chart.size.cx - chart.rightVScaleWidth + tSize.cx, bottom:drawY + tSize.cy / 2 + 3)
            paint.drawText(text:rightText, color:chart.textColor, font:chart.font, x:chart.size.cx - chart.rightVScaleWidth, y:drawY - tSize.cy / 2)
        }
        //绘制十字线
        var drawX = getChartX(chart: chart, index: chart.crossStopIndex)
        if chart.targetOldX == 0 || chart.targetOldX2 == 0{
            drawX = chart.touchPosition.x
        }
        if drawX < chart.leftVScaleWidth {
            drawX = chart.leftVScaleWidth
        }
        if drawX > chart.size.cx - chart.rightVScaleWidth {
            drawX = chart.size.cx - chart.rightVScaleWidth
        }
        if !chart.getSelectedPlot().isNotEmpty && chart.selectShape == "" {
            paint.drawLine(color:chart.crossLineColor, width:chart.lineWidthChart, style:[], x1:chart.leftVScaleWidth, y1:drawY, x2:chart.size.cx - chart.rightVScaleWidth, y2:drawY)
            paint.drawLine(color:chart.crossLineColor, width:chart.lineWidthChart, style:[], x1:drawX, y1:0, x2:drawX, y2:chart.size.cy - chart.hScaleHeight)
        }
        if chart.crossStopIndex != -1 {
            var xText = ""
            let timeInterval:TimeInterval = TimeInterval(chart.data[chart.crossStopIndex].date)
            let date = Date(timeIntervalSince1970: timeInterval)
            let dateformatter = DateFormatter()
            if chart.hScaleFormat.count > 0 {
                dateformatter.dateFormat = chart.hScaleFormat
                xText =  dateformatter.string(from:date)
            } else {
                if chart.cycle == "day" {
                    dateformatter.dateFormat = "YYYY-mm-dd"
                    xText =  dateformatter.string(from:date)
                } else if chart.cycle == "minute" {
                    dateformatter.dateFormat = "YYYY-mm-dd HH:MM"
                    xText =  dateformatter.string(from:date)
                } else if chart.cycle == "trend" {
                    dateformatter.dateFormat = "HH:MM"
                    xText =  dateformatter.string(from:date)
                }else if chart.cycle == "second" {
                    dateformatter.dateFormat = "HH:MM:SS"
                    xText = dateformatter.string(from:date)
                }else if chart.cycle == "tick" {
                    xText = String(chart.crossStopIndex + 1)
                }
            }
            let xSize = paint.textSize(text:xText, font:chart.font)
            paint.fillRect(color:chart.crossTipColor, left:drawX - xSize.cx / 2 - 2, top:candleDivHeight + volDivHeight + indDivHeight, right:drawX + xSize.cx / 2 + 2, bottom:candleDivHeight + volDivHeight + indDivHeight + xSize.cy + 6)
            paint.drawText(text:xText, color:chart.textColor, font:chart.font, x:drawX - xSize.cx / 2, y:candleDivHeight + volDivHeight + indDivHeight + 3)
        }
    }
}

/*
* 计算最大最小值
* chart:图表
*/
func calculateChartMaxMin(chart:FCChart) {
    chart.candleMax = 0
    chart.candleMin = 0
    chart.volMax = 0
    chart.volMin = 0
    chart.indMin = 0
    chart.indMin = 0
    var load1 = false
    var load2 = false
    var load3 = false
    var load4 = false
    let isTrend = chart.cycle == "trend"
    var firstOpen:Double = chart.firstOpen
    if chart.data.count > 0 {
        var lastValidIndex = chart.lastVisibleIndex
        if chart.lastValidIndex != -1 {
            lastValidIndex = chart.lastValidIndex
        }
        for i in chart.firstVisibleIndex...lastValidIndex {
            if i == chart.firstVisibleIndex {
                if isTrend {
                    chart.candleMax = chart.data[i].close
                    chart.candleMin = chart.data[i].close
                    if(firstOpen == 0){
                        firstOpen = chart.data[i].close
                    }
                } else {
                    chart.candleMax = chart.data[i].high
                    chart.candleMin = chart.data[i].low
                }
                chart.volMax = chart.data[i].volume
                load1 = true
                load2 = true
                if chart.showIndicator == "MACD" {
                    chart.indMax = chart.alldifarr[i]
                    chart.indMin = chart.alldifarr[i]
                    load3 = true
                }
                else if chart.showIndicator == "KDJ" {
                    chart.indMax = chart.kdjK[i]
                    chart.indMin = chart.kdjK[i]
                    load3 = true
                }
                else if chart.showIndicator == "RSI" {
                    chart.indMax = chart.rsi1[i]
                    chart.indMin = chart.rsi1[i]
                    load3 = true
                }
                else if chart.showIndicator == "BIAS" {
                    chart.indMax = chart.bias1[i]
                    chart.indMin = chart.bias1[i]
                    load3 = true
                }
                else if chart.showIndicator == "ROC" {
                    chart.indMax = chart.roc[i]
                    chart.indMin = chart.roc[i]
                    load3 = true
                }
                else if chart.showIndicator == "WR" {
                    chart.indMax = chart.wr1[i]
                    chart.indMin = chart.wr1[i]
                    load3 = true
                } else if chart.showIndicator == "CCI" {
                    chart.indMax = chart.cci[i]
                    chart.indMin = chart.cci[i]
                    load3 = true
                } else if chart.showIndicator == "BBI" {
                    chart.indMax = chart.bbi[i]
                    chart.indMin = chart.bbi[i]
                    load3 = true
                }
                else if chart.showIndicator == "TRIX" {
                    chart.indMax = chart.trix[i]
                    chart.indMin = chart.trix[i]
                    load3 = true
                }
                else if chart.showIndicator == "DMA" {
                    chart.indMax = chart.dma1[i]
                    chart.indMin = chart.dma1[i]
                    load3 = true
                }
            }else {
                if isTrend {
                    if chart.candleMax < chart.data[i].close {
                        chart.candleMax = chart.data[i].close
                    }
                    if chart.candleMin > chart.data[i].close {
                        chart.candleMin = chart.data[i].close
                    }
                } else {
                    if chart.candleMax < chart.data[i].high {
                        chart.candleMax = chart.data[i].high
                    }
                    if chart.candleMin > chart.data[i].low {
                        chart.candleMin = chart.data[i].low
                    }
                }
                if chart.volMax < chart.data[i].volume {
                    chart.volMax = chart.data[i].volume
                }
            }
            if chart.showIndicator == "MACD" {
                if chart.indMax < chart.alldifarr[i] {
                    chart.indMax = chart.alldifarr[i]
                }
                if chart.indMax < chart.alldeaarr[i] {
                    chart.indMax = chart.alldeaarr[i]
                }
                if chart.indMax < chart.allmacdarr[i] {
                    chart.indMax = chart.allmacdarr[i]
                }
                if chart.indMin > chart.alldifarr[i] {
                    chart.indMin = chart.alldifarr[i]
                }
                if chart.indMin > chart.alldeaarr[i] {
                    chart.indMin = chart.alldeaarr[i]
                }
                if chart.indMin > chart.allmacdarr[i] {
                    chart.indMin = chart.allmacdarr[i]
                }
            } else if chart.showIndicator == "KDJ" {
                if chart.indMax < chart.kdjK[i] {
                    chart.indMax = chart.kdjK[i]
                }
                if chart.indMax < chart.kdjD[i] {
                    chart.indMax = chart.kdjD[i]
                }
                if chart.indMax < chart.kdjJ[i] {
                    chart.indMax = chart.kdjJ[i]
                }
                if chart.indMin > chart.kdjK[i] {
                    chart.indMin = chart.kdjK[i]
                }
                if chart.indMin > chart.kdjD[i] {
                    chart.indMin = chart.kdjD[i]
                }
                if chart.indMin > chart.kdjJ[i] {
                    chart.indMin = chart.kdjJ[i]
                }
            } else if chart.showIndicator == "RSI" {
                if chart.indMax < chart.rsi1[i] {
                    chart.indMax = chart.rsi1[i]
                }
                if chart.indMax < chart.rsi2[i] {
                    chart.indMax = chart.rsi2[i]
                }
                if chart.indMax < chart.rsi3[i] {
                    chart.indMax = chart.rsi3[i]
                }
                if chart.indMin > chart.rsi1[i] {
                    chart.indMin = chart.rsi1[i]
                }
                if chart.indMin > chart.rsi2[i] {
                    chart.indMin = chart.rsi2[i]
                }
                if chart.indMin > chart.rsi3[i] {
                    chart.indMin = chart.rsi3[i]
                }
            } else if chart.showIndicator == "BIAS" {
                if chart.indMax < chart.bias1[i] {
                    chart.indMax = chart.bias1[i]
                }
                if chart.indMax < chart.bias2[i] {
                    chart.indMax = chart.bias2[i]
                }
                if chart.indMax < chart.bias3[i] {
                    chart.indMax = chart.bias3[i]
                }
                if chart.indMin > chart.bias1[i] {
                    chart.indMin = chart.bias1[i]
                }
                if chart.indMin > chart.bias2[i] {
                    chart.indMin = chart.bias2[i]
                }
                if chart.indMin > chart.bias3[i] {
                    chart.indMin = chart.bias3[i]
                }
            } else if chart.showIndicator == "ROC" {
                if chart.indMax < chart.roc[i] {
                    chart.indMax = chart.roc[i]
                }
                if chart.indMax < chart.rocMa[i] {
                    chart.indMax = chart.rocMa[i]
                }
                if chart.indMin > chart.roc[i] {
                    chart.indMin = chart.roc[i]
                }
                if chart.indMin > chart.rocMa[i] {
                    chart.indMin = chart.rocMa[i]
                }
            }
            else if chart.showIndicator == "WR" {
                if chart.indMax < chart.wr1[i] {
                    chart.indMax = chart.wr1[i]
                }
                if chart.indMax < chart.wr2[i] {
                    chart.indMax = chart.wr2[i]
                }
                if chart.indMin > chart.wr1[i] {
                    chart.indMin = chart.wr1[i]
                }
                if chart.indMin > chart.wr2[i] {
                    chart.indMin = chart.wr2[i]
                }
            } else if chart.showIndicator == "CCI" {
                if chart.indMax < chart.cci[i] {
                    chart.indMax = chart.cci[i]
                }
                if chart.indMin > chart.cci[i] {
                    chart.indMin = chart.cci[i]
                }
            } else if chart.showIndicator == "BBI" {
                if chart.indMax < chart.bbi[i] {
                    chart.indMax = chart.bbi[i]
                }
                if chart.indMin > chart.bbi[i] {
                    chart.indMin = chart.bbi[i]
                }
            } else if chart.showIndicator == "TRIX" {
                if chart.indMax < chart.trix[i] {
                    chart.indMax = chart.trix[i]
                }
                if chart.indMax < chart.trixMa[i] {
                    chart.indMax = chart.trixMa[i]
                }
                if chart.indMin > chart.trix[i] {
                    chart.indMin = chart.trix[i]
                }
                if chart.indMin > chart.trixMa[i] {
                    chart.indMin = chart.trixMa[i]
                }
            } else if chart.showIndicator == "DMA" {
                if chart.indMax < chart.dma1[i] {
                    chart.indMax = chart.dma1[i]
                }
                if chart.indMax < chart.dma2[i] {
                    chart.indMax = chart.dma2[i]
                }
                if chart.indMin > chart.dma1[i]{
                    chart.indMin = chart.dma1[i]
                }
                if chart.indMin > chart.dma2[i] {
                    chart.indMin = chart.dma2[i]
                }
            }
        }
    }
    if chart.shapes.count > 0 {
        var lastValidIndex = chart.lastVisibleIndex
        if chart.lastValidIndex != -1 {
            lastValidIndex = chart.lastValidIndex
        }
        for s in 0...chart.shapes.count - 1{
            let shape = chart.shapes[s]
            if shape.datas.count > 0 {
                for i in chart.firstVisibleIndex...lastValidIndex {
                    if shape.divIndex == 0 {
                        if !load1 && i == chart.firstVisibleIndex {
                            if shape.leftOrRight {
                                chart.candleMax = shape.datas[i]
                                chart.candleMin = shape.datas[i]
                            } else {
                                chart.candleMaxRight = shape.datas[i]
                                chart.candleMinRight = shape.datas[i]
                            }
                            load1 = true
                        } else {
                            if shape.leftOrRight {
                                if shape.datas[i] > chart.candleMax {
                                    chart.candleMax = shape.datas[i]
                                }
                                if shape.datas[i] < chart.candleMin {
                                    chart.candleMin = shape.datas[i]
                                }
                            } else {
                                if shape.datas[i] > chart.candleMaxRight {
                                    chart.candleMaxRight = shape.datas[i]
                                }
                                if shape.datas[i] < chart.candleMinRight {
                                    chart.candleMinRight = shape.datas[i]
                                }
                            }
                        }
                    } else if shape.divIndex == 1 {
                        if !load2 && i == chart.firstVisibleIndex {
                            if shape.leftOrRight {
                                chart.volMax = shape.datas[i]
                                chart.volMin = shape.datas[i]
                            } else {
                                chart.volMaxRight = shape.datas[i]
                                chart.volMinRight = shape.datas[i]
                            }
                            load2 = true
                        } else {
                            if shape.leftOrRight {
                                if shape.datas[i] > chart.volMax {
                                    chart.volMax = shape.datas[i]
                                }
                                if shape.datas[i] < chart.volMin {
                                    chart.volMin = shape.datas[i]
                                }
                            } else {
                                if shape.datas[i] > chart.volMaxRight {
                                    chart.volMaxRight = shape.datas[i]
                                }
                                if shape.datas[i] < chart.volMinRight {
                                    chart.volMinRight = shape.datas[i]
                                }
                            }
                        }
                    } else if shape.divIndex == 2 {
                        if !load3 && i == chart.firstVisibleIndex{
                            if shape.leftOrRight {
                                chart.indMax = shape.datas[i]
                                chart.indMin = shape.datas[i]
                            } else {
                                chart.indMaxRight = shape.datas[i]
                                chart.indMinRight = shape.datas[i]
                            }
                            load3 = true
                        } else {
                            if shape.leftOrRight {
                                if shape.datas[i] > chart.indMax {
                                    chart.indMax = shape.datas[i]
                                }
                                if shape.datas[i] < chart.indMin{
                                    chart.indMin = shape.datas[i]
                                }
                            } else {
                                if shape.datas[i] > chart.indMaxRight {
                                    chart.indMaxRight = shape.datas[i]
                                }
                                if shape.datas[i] < chart.indMinRight {
                                    chart.indMinRight = shape.datas[i]
                                }
                            }
                        }
                    } else if shape.divIndex == 3 {
                        if !load4 && i == chart.firstVisibleIndex {
                            if shape.leftOrRight {
                                chart.indMax2 = shape.datas[i]
                                chart.indMin2 = shape.datas[i]
                            } else {
                                chart.indMax2Right = shape.datas[i]
                                chart.indMin2Right = shape.datas[i]
                            }
                            load4 = true
                        } else {
                            if shape.leftOrRight {
                                if shape.datas[i] > chart.indMax2 {
                                    chart.indMax2 = shape.datas[i]
                                }
                                if shape.datas[i] < chart.indMin2 {
                                    chart.indMin2 = shape.datas[i]
                                }
                            } else {
                                if shape.datas[i] > chart.indMax2Right {
                                    chart.indMax2Right = shape.datas[i]
                                }
                                if shape.datas[i] < chart.indMin2Right {
                                    chart.indMin2Right = shape.datas[i]
                                }
                            }
                        }
                    }
                }
            }
            if shape.datas2.count > 0 {
                for i in chart.firstVisibleIndex...lastValidIndex {
                    if shape.divIndex == 0 {
                        if shape.leftOrRight {
                            if shape.datas2[i] > chart.candleMax {
                                chart.candleMax = shape.datas2[i]
                            }
                            if shape.datas2[i] < chart.candleMin {
                                chart.candleMin = shape.datas2[i]
                            }
                        } else {
                            if shape.datas2[i] > chart.candleMaxRight {
                                chart.candleMaxRight = shape.datas2[i]
                            }
                            if shape.datas2[i] < chart.candleMinRight {
                                chart.candleMinRight = shape.datas2[i]
                            }
                        }
                    } else if shape.divIndex == 1 {
                        if shape.leftOrRight {
                            if shape.datas2[i] > chart.volMax {
                                chart.volMax = shape.datas2[i]
                            }
                            if shape.datas2[i] < chart.volMin {
                                chart.volMin = shape.datas2[i]
                            }
                        } else {
                            if shape.datas2[i] > chart.volMaxRight {
                                chart.volMaxRight = shape.datas2[i]
                            }
                            if shape.datas2[i] < chart.volMinRight{
                                chart.volMinRight = shape.datas2[i]
                            }
                        }
                    } else if shape.divIndex == 2 {
                        if shape.leftOrRight {
                            if shape.datas2[i] > chart.indMax {
                                chart.indMax = shape.datas2[i]
                            }
                            if shape.datas2[i] < chart.indMin {
                                chart.indMin = shape.datas2[i]
                            }
                        } else {
                            if shape.datas2[i] > chart.indMaxRight {
                                chart.indMaxRight = shape.datas2[i]
                            }
                            if shape.datas2[i] < chart.indMinRight {
                                chart.indMinRight = shape.datas2[i]
                            }
                        }
                    } else if shape.divIndex == 3 {
                        if shape.leftOrRight {
                            if shape.datas2[i] > chart.indMax2 {
                                chart.indMax2 = shape.datas2[i]
                            }
                            if shape.datas2[i] < chart.indMin2 {
                                chart.indMin2 = shape.datas2[i]
                            }
                        } else {
                            if shape.datas2[i] > chart.indMax2Right {
                                chart.indMax2Right = shape.datas2[i]
                            }
                            if shape.datas2[i] < chart.indMin2Right {
                                chart.indMin2Right = shape.datas2[i]
                            }
                        }
                    }
                }
            }
        }
    }
    if isTrend {
        let subMax = max(abs(chart.candleMax - firstOpen), abs(chart.candleMin - firstOpen))
        chart.candleMax = firstOpen + subMax
        chart.candleMin = firstOpen - subMax
    } else {
        if chart.candleMax == 0 && chart.candleMin == 0 {
            chart.candleMax = 1
            chart.candleMin = -1
        }
        if chart.volMax == 0 && chart.volMin == 0 {
            chart.volMax = 1
            chart.volMin = -1
        }
        if chart.indMax == 0 && chart.indMin == 0 {
            chart.indMax = 1
            chart.indMin = -1
        }
        if chart.indMax2 == 0 && chart.indMin2 == 0 {
            chart.indMax2 = 1
            chart.indMin2 = -1
        }
        if chart.candleMaxRight == 0 && chart.candleMinRight == 0 {
            chart.candleMaxRight = 1
            chart.candleMinRight = -1
        }
        if chart.volMaxRight == 0 && chart.volMinRight == 0 {
            chart.volMaxRight = 1
            chart.volMinRight = -1
        }
        if chart.indMaxRight == 0 && chart.indMinRight == 0 {
            chart.indMaxRight = 1
            chart.indMinRight = -1
        }
        if chart.indMax2Right == 0 && chart.indMin2Right == 0 {
            chart.indMax2Right = 1
            chart.indMin2Right = -1
        }
    }
}

/*
* 绘制线条
* chart:图表
* paint:绘图对象
* clipRect:裁剪区域
* divIndex:图层
* datas:数据
* color:颜色
* selected:是否选中
*/
func drawChartLines(chart:FCChart, paint:FCPaint, clipRect:FCRect, divIndex:Int, datas:[Double], color:String, selected:Bool) {
    paint.beginPath()
    var lastX:Double = 0
    var lastY:Double = 0
    let maxVisibleRecord = getChartMaxVisibleCount(chart:chart, hScalePixel:chart.hScalePixel, pureH:getChartWorkAreaWidth(chart:chart))
    var lastValidIndex = chart.lastVisibleIndex
    if chart.lastValidIndex != -1 {
        lastValidIndex = chart.lastValidIndex
    }
    var sRect = [FCRect]()
    for i in chart.firstVisibleIndex...lastValidIndex {
        let x = getChartX(chart:chart, index:i)
        let value = datas[i]
        let y = getChartY(chart:chart, divIndex:divIndex, value:value)
        if i > chart.firstVisibleIndex {
            paint.addLine(x1:lastX, y1:lastY, x2:x, y2:y)
        }
        lastX = x
        lastY = y
        if selected {
            var kPInterval = Int(maxVisibleRecord / 30)
            if kPInterval < 2 {
                kPInterval = 3
            }
            if i % kPInterval == 0 {
                let rect = FCRect(left:x - 3, top:y - 3, right:x + 3, bottom:y + 3)
                sRect.append(rect)
            }
        }
    }
    paint.drawPath(color:color, width:chart.lineWidthChart, style:[])
    paint.closePath()
    if sRect.count > 0{
        for i in 0...sRect.count - 1{
            let rect = sRect[i]
            paint.fillRect(color:color, left:rect.left, top:rect.top, right:rect.right, bottom:rect.bottom)
        }
    }
}


/*
* 绘制线条到右轴
* chart:图表
* paint:绘图对象
* clipRect:裁剪区域
* divIndex:图层
* datas:数据
* color:颜色
* selected:是否选中
*/
func drawChartLinesInRight(chart:FCChart, paint:FCPaint, clipRect:FCRect, divIndex:Int, datas:[Double], color:String, selected:Bool) {
    paint.beginPath()
    var lastX:Double = 0
    var lastY:Double = 0
    let maxVisibleRecord = getChartMaxVisibleCount(chart:chart, hScalePixel:chart.hScalePixel, pureH:getChartWorkAreaWidth(chart:chart))
    var lastValidIndex = chart.lastVisibleIndex
    if chart.lastValidIndex != -1{
        lastValidIndex = chart.lastValidIndex
    }
    var sRect = [FCRect]()
    for i in chart.firstVisibleIndex...lastValidIndex {
        let x = getChartX(chart:chart, index:i)
        let value = datas[i]
        let y = getChartYInRight(chart:chart, divIndex:divIndex, value:value)
        if i > chart.firstVisibleIndex {
            paint.addLine(x1:lastX, y1:lastY, x2:x, y2:y)
        }
        lastX = x
        lastY = y
        if selected {
            var kPInterval = Int(maxVisibleRecord / 30)
            if kPInterval < 2 {
                kPInterval = 3
            }
            if i % kPInterval == 0 {
                let rect = FCRect(left:x - 3, top:y - 3, right:x + 3, bottom:y + 3)
                sRect.append(rect)
            }
        }
    }
    paint.drawPath(color:color, width:chart.lineWidthChart, style:[])
    paint.closePath()
    if sRect.count > 0{
        for i in 0...sRect.count - 1{
            let rect = sRect[i]
            paint.fillRect(color:color, left:rect.left, top:rect.top, right:rect.right, bottom:rect.bottom)
        }
    }
}

/*
* 绘制画线工具
* chart:图表
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawChartPlot(chart:FCChart, paint:FCPaint, clipRect:FCRect) {
    if chart.plots.count > 0{
        paint.save()
        let divHeight = getCandleDivHeight(chart:chart)
        paint.setClip(left:chart.leftVScaleWidth, top:0, right:chart.size.cx - chart.rightVScaleWidth, bottom:divHeight)
        for i in 0...chart.plots.count - 1{
            let plot = chart.plots[i]
            var index1 = 0, index2 = 0, index3 = 0
            var mpx1 = 0.0, mpy1 = 0.0, mpx2 = 0.0, mpy2 = 0.0, mpx3 = 0.0, mpy3 = 0.0
            if plot.plotType == "LRLine" || plot.plotType == "LRChannel" || plot.plotType == "LRBand" {
                var list = [Double]()
                index1 = getChartIndexByDate(chart:chart, date:plot.key1)
                index2 = getChartIndexByDate(chart:chart, date:plot.key2)
                let minIndex = min(index1, index2)
                let maxIndex = max(index1, index2)
                for j in minIndex...maxIndex{
                    list.append(chart.data[j].close)
                }
                linearRegressionEquation(chart:chart, list:list)
                plot.value1 = chart.bChart
                plot.value2 = chart.kChart * Double(maxIndex - minIndex + 1) + chart.bChart
            }else if plot.plotType == "BoxLine" || plot.plotType == "TironeLevels" || plot.plotType == "QuadrantLines" {
                getCandleRange(chart:chart, plot:plot)
                let nHigh = chart.nHighChart, nLow = chart.nLowChart
                index1 = getChartIndexByDate(chart:chart, date:plot.key1)
                index2 = getChartIndexByDate(chart:chart, date:plot.key2)
                plot.key1 = getChartDateByIndex(chart:chart, index:min(index1, index2))
                plot.key2 = getChartDateByIndex(chart:chart, index:max(index1, index2))
                plot.value1 = nHigh
                plot.value2 = nLow
            }
            if plot.key1 > 0{
                index1 = getChartIndexByDate(chart:chart, date:plot.key1)
                mpx1 = getChartX(chart:chart, index:index1)
                mpy1 = getChartY(chart:chart, divIndex:0, value:plot.value1)
                if chart.getSelectedPlot() == plot {
                    paint.fillEllipse(color:plot.pointColor, left:mpx1 - chart.plotPointSizeChart, top:mpy1 - chart.plotPointSizeChart, right:mpx1 + chart.plotPointSizeChart, bottom:mpy1 + chart.plotPointSizeChart)
                }
            }
            if plot.key2 > 0 {
                index2 = getChartIndexByDate(chart:chart, date:plot.key2)
                mpx2 = getChartX(chart:chart, index:index2)
                mpy2 = getChartY(chart:chart, divIndex:0, value:plot.value2)
                if chart.getSelectedPlot() == plot {
                    paint.fillEllipse(color:plot.pointColor, left:mpx2 - chart.plotPointSizeChart, top:mpy2 - chart.plotPointSizeChart, right:mpx2 + chart.plotPointSizeChart, bottom:mpy2 + chart.plotPointSizeChart)
                }
            }
            if plot.key3 > 0 {
                index3 = getChartIndexByDate(chart:chart, date:plot.key3)
                mpx3 = getChartX(chart:chart, index:index3)
                mpy3 = getChartY(chart:chart, divIndex:0, value:plot.value3)
                if chart.getSelectedPlot() == plot {
                    paint.fillEllipse(color:plot.pointColor, left:mpx3 - chart.plotPointSizeChart, top:mpy3 - chart.plotPointSizeChart, right:mpx3 + chart.plotPointSizeChart, bottom:mpy3 + chart.plotPointSizeChart)
                }
            }
            if plot.plotType == "Line" {
                lineXY(chart:chart, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2, oX:0, oY:0)
                if mpx2 == mpx1 {
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:0, x2:mpx1, y2:divHeight)
                } else {
                    let newX1 = chart.leftVScaleWidth
                    let newY1 = newX1 * chart.kChart + chart.bChart
                    let newX2 = chart.size.cx - chart.rightVScaleWidth
                    let newY2 = newX2 * chart.kChart + chart.bChart
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:newX1, y1:newY1, x2:newX2, y2:newY2)
                }
            }
            else if plot.plotType == "AngleLine" {
                lineXY(chart:chart, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2, oX:0, oY:0)
                if mpx2 == mpx1 {
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:0, x2:mpx1, y2:divHeight)
                } else {
                    let newX1 = chart.leftVScaleWidth
                    let newY1 = newX1 * chart.kChart + chart.bChart
                    let newX2 = chart.size.cx - chart.rightVScaleWidth
                    let newY2 = newX2 * chart.kChart + chart.bChart
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:newX1, y1:newY1, x2:newX2, y2:newY2)
                }
                lineXY(chart:chart, x1:mpx1, y1:mpy1, x2:mpx3, y2:mpy3, oX:0, oY:0)
                if mpx3 == mpx1 {
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:0, x2:mpx1, y2:divHeight)
                } else {
                    let newX1 = chart.leftVScaleWidth
                    let newY1 = newX1 * chart.kChart + chart.bChart
                    let newX2 = chart.size.cx - chart.rightVScaleWidth
                    let newY2 = newX2 * chart.kChart + chart.bChart
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:newX1, y1:newY1, x2:newX2, y2:newY2)
                }
            }else if plot.plotType == "Parallel" {
                lineXY(chart:chart, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2, oX:0, oY:0)
                if mpx2 == mpx1 {
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:0, x2:mpx1, y2:divHeight)
                } else {
                    let newX1 = chart.leftVScaleWidth
                    let newY1 = newX1 * chart.kChart + chart.bChart
                    let newX2 = chart.size.cx - chart.rightVScaleWidth
                    let newY2 = newX2 * chart.kChart + chart.bChart
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:newX1, y1:newY1, x2:newX2, y2:newY2)
                }
                let newB = mpy3 - chart.kChart * mpx3
                if mpx2 == mpx1 {
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx3, y1:0, x2:mpx3, y2:divHeight)
                } else {
                    let newX1 = chart.leftVScaleWidth
                    let newY1 = newX1 * chart.kChart + newB
                    let newX2 = chart.size.cx - chart.rightVScaleWidth
                    let newY2 = newX2 * chart.kChart + newB
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:newX1, y1:newY1, x2:newX2, y2:newY2)
                }
            }
            else if plot.plotType == "Percent" {
                let list = getPercentParams(y1:mpy1, y2:mpy2)
                var texts = [String]()
                texts.append("0%")
                texts.append("25%")
                texts.append("50%")
                texts.append("75%")
                texts.append("100%")
                for j in 0...list.count - 1{
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:chart.leftVScaleWidth, y1:list[j], x2:chart.size.cx - chart.rightVScaleWidth, y2:list[j])
                    let tSize = paint.textSize(text:texts[j], font:chart.font)
                    paint.drawText(text:texts[j], color:chart.textColor, font:chart.font, x:chart.leftVScaleWidth + 5, y:list[j] - tSize.cy - 2)
                }
            }else if plot.plotType == "FiboTimezone" {
                var fValue = 1
                let aIndex = index1
                var pos = 1
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:0, x2:mpx1, y2:divHeight)
                let tSize = paint.textSize(text:"1", font:chart.font)
                paint.drawText(text:"1", color:chart.textColor, font:chart.font, x:mpx1, y:divHeight - tSize.cy)
                while aIndex + fValue <= chart.lastVisibleIndex {
                    fValue = fibonacciValue(index:pos)
                    let newIndex = aIndex + fValue
                    let newX = getChartX(chart:chart, index:newIndex)
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:newX, y1:0, x2:newX, y2:divHeight)
                    let tSize2 = paint.textSize(text:String(fValue), font:chart.font)
                    paint.drawText(text:String(fValue), color:chart.textColor, font:chart.font, x:newX, y:divHeight - tSize2.cy)
                    pos += 1
                }
            }else if plot.plotType == "SpeedResist" {
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                if mpx1 != mpx2 && mpy1 != mpy2 {
                    let firstP = FCPoint(x:mpx2, y:mpy2 - (mpy2 - mpy1) / 3)
                    let secondP = FCPoint(x:mpx2, y:mpy2 - (mpy2 - mpy1) * 2 / 3)
                    let startP = FCPoint(x:mpx1, y:mpy1)
                    var fK = 0.0, fB = 0.0, sK = 0.0, sB = 0.0
                    lineXY(chart:chart, x1:startP.x, y1:startP.y, x2:firstP.x, y2:firstP.y, oX:0, oY:0)
                    fK = chart.kChart
                    fB = chart.bChart
                    lineXY(chart:chart, x1:startP.x, y1:startP.y, x2:secondP.x, y2:secondP.y, oX:0, oY:0)
                    sK = chart.kChart
                    sB = chart.bChart
                    var newYF = 0.0, newYS = 0.0
                    var newX = 0.0
                    if mpx2 > mpx1 {
                        newYF = fK * (chart.size.cx - chart.rightVScaleWidth) + fB
                        newYS = sK * (chart.size.cx - chart.rightVScaleWidth) + sB
                        newX = (chart.size.cx - chart.rightVScaleWidth)
                    }
                    else {
                        newYF = fB
                        newYS = sB
                        newX = chart.leftVScaleWidth
                    }
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:startP.x, y1:startP.y, x2:newX, y2:newYF)
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:startP.x, y1:startP.y, x2:newX, y2:newYS)
                }
            }else if plot.plotType == "FiboFanline" {
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                if mpx1 != mpx2 && mpy1 != mpy2 {
                    let firstP = FCPoint(x:mpx2, y:mpy2 - (mpy2 - mpy1) * 0.382)
                    let secondP = FCPoint(x:mpx2, y:mpy2 - (mpy2 - mpy1) * 0.5)
                    let thirdP = FCPoint(x:mpx2, y:mpy2 - (mpy2 - mpy1) * 0.618)
                    let startP = FCPoint(x:mpx1, y:mpy1)
                    var listP = [FCPoint]()
                    listP.append(firstP)
                    listP.append(secondP)
                    listP.append(thirdP)
                    let listSize = listP.count
                    for j in 0...listSize - 1{
                        //获取直线参数
                        lineXY(chart:chart, x1:startP.x, y1:startP.y, x2:listP[j].x, y2:listP[j].y, oX:0, oY:0)
                        var newX = 0.0
                        var newY = 0.0
                        if mpx2 > mpx1 {
                            newY = chart.kChart * (chart.size.cx - chart.rightVScaleWidth) + chart.bChart
                            newX = (chart.size.cx - chart.rightVScaleWidth)
                        }
                        else {
                            newY = chart.bChart
                            newX = chart.leftVScaleWidth
                        }
                        paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:startP.x, y1:startP.y, x2:newX, y2:newY)
                    }
                }
            }else if plot.plotType == "LRLine" {
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
            }else if plot.plotType == "LRBand" {
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                getLRBandRange(chart:chart, plot:plot, a:chart.kChart, b:chart.bChart)
                mpy1 = getChartY(chart:chart, divIndex:0, value:plot.value1 + chart.upSubValue)
                mpy2 = getChartY(chart:chart, divIndex:0, value:plot.value2 + chart.upSubValue)
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                mpy1 = getChartY(chart:chart, divIndex:0, value:plot.value1 - chart.downSubValue)
                mpy2 = getChartY(chart:chart, divIndex:0, value:plot.value2 - chart.downSubValue)
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
            }else if plot.plotType == "LRChannel" {
                getLRBandRange(chart:chart, plot:plot, a:chart.kChart, b:chart.bChart)
                lineXY(chart:chart, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2, oX:0, oY:0)
                let rightX = chart.size.cx - chart.rightVScaleWidth
                var rightY = rightX * chart.kChart + chart.bChart
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:mpy1, x2:rightX, y2:rightY)
                mpy1 = getChartY(chart:chart, divIndex:0, value:plot.value1 + chart.upSubValue)
                mpy2 = getChartY(chart:chart, divIndex:0, value:plot.value2 + chart.upSubValue)
                lineXY(chart:chart, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2, oX:0, oY:0)
                rightY = rightX * chart.kChart + chart.bChart
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:mpy1, x2:rightX, y2:rightY)
                mpy1 = getChartY(chart:chart, divIndex:0, value:plot.value1 - chart.downSubValue)
                mpy2 = getChartY(chart:chart, divIndex:0, value:plot.value2 - chart.downSubValue)
                lineXY(chart:chart, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2, oX:0, oY:0)
                rightY = rightX * chart.kChart + chart.bChart
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:mpy1, x2:rightX, y2:rightY)
            }else if plot.plotType == "Segment" {
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
            } else if plot.plotType == "Ray" {
                lineXY(chart:chart, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2, oX:0, oY:0)
                if chart.kChart != 0 || chart.bChart != 0 {
                    let leftX = chart.leftVScaleWidth
                    let leftY = leftX * chart.kChart + chart.bChart
                    let rightX = chart.size.cx - chart.rightVScaleWidth
                    let rightY = rightX * chart.kChart + chart.bChart
                    if mpx1 >= mpx2 {
                        paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:leftX, y1:leftY, x2:mpx1, y2:mpy1)
                    } else {
                        paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:mpy1, x2:rightX, y2:rightY)
                    }
                }
                //垂直时
                else {
                    if mpy1 >= mpy2 {
                        paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:mpy1, x2:mpx1, y2:0)
                    } else {
                        paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:mpy1, x2:mpx1, y2:divHeight)
                    }
                }
            }else if plot.plotType == "Triangle" {
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx2, y1:mpy2, x2:mpx3, y2:mpy3)
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:mpy1, x2:mpx3, y2:mpy3)
            }else if plot.plotType == "SymmetricTriangle" {
                if mpx2 != mpx1 {
                    let a = (mpy2 - mpy1) / (mpx2 - mpx1)
                    let b = mpy1 - a * mpx1
                    let c = -a
                    let d = mpy3 - c * mpx3
                    let leftX = chart.leftVScaleWidth
                    var leftY = leftX * a + b
                    let rightX = chart.size.cx - chart.rightVScaleWidth
                    var rightY = rightX * a + b
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:leftX, y1:leftY, x2:rightX, y2:rightY)
                    leftY = leftX * c + d
                    rightY = rightX * c + d
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:leftX, y1:leftY, x2:rightX, y2:rightY)
                } else {
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:0, x2:mpx1, y2:divHeight)
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx3, y1:0, x2:mpx3, y2:divHeight)
                }
            }else if plot.plotType == "Rect" {
                let sX1 = min(mpx1, mpx2)
                let sY1 = min(mpy1, mpy2)
                let sX2 = max(mpx1, mpx2)
                let sY2 = max(mpy1, mpy2)
                paint.drawRect(color:plot.lineColor, width:plot.lineWidth, style:[], left:sX1, top:sY1, right:sX2, bottom:sY2)
            } else if plot.plotType == "Cycle" {
                let r = sqrt(abs((mpx2 - mpx1) * (mpx2 - mpx1) + (mpy2 - mpy1) * (mpy2 - mpy1)))
                paint.drawEllipse(color:plot.lineColor, width:plot.lineWidth, style:[], left:mpx1 - r, top:mpy1 - r, right:mpx1 + r, bottom:mpy1 + r)
            } else if plot.plotType == "CircumCycle" {
                ellipseOR(chart:chart, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2, x3:mpx3, y3:mpy3)
                paint.drawEllipse(color:plot.lineColor, width:plot.lineWidth, style:[], left:chart.oXChart - chart.rChart, top:chart.oYChart - chart.rChart, right:chart.oXChart + chart.rChart, bottom:chart.oYChart + chart.rChart)
            }else if plot.plotType == "Ellipse" {
                var x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0
                if mpx1 <= mpx2 {
                    x1 = mpx2
                    y1 = mpy2
                    x2 = mpx1
                    y2 = mpy1
                } else {
                    x1 = mpx1
                    y1 = mpy1
                    x2 = mpx2
                    y2 = mpy2
                }
                let x = x1 - (x1 - x2)
                var y = 0.0
                let width = (x1 - x2) * 2
                var height = 0.0
                if y1 >= y2 {
                    height = (y1 - y2) * 2
                }
                else {
                    height = (y2 - y1) * 2
                }
                y = y2 - height / 2
                paint.drawEllipse(color:plot.lineColor, width:plot.lineWidth, style:[], left:x, top:y, right:x + width, bottom:y + height)
            }else if plot.plotType == "ParalleGram" {
                parallelogram(chart:chart, x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2, x3:mpx3, y3:mpy3)
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx1, y1:mpy1, x2:mpx2, y2:mpy2)
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx2, y1:mpy2, x2:mpx3, y2:mpy3)
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:mpx3, y1:mpy3, x2:chart.x4Chart, y2:chart.y4Chart)
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:chart.x4Chart, y1:chart.y4Chart, x2:mpx1, y2:mpy1)
            }else if plot.plotType == "BoxLine" {
                let sX1 = min(mpx1, mpx2)
                let sY1 = min(mpy1, mpy2)
                let sX2 = max(mpx1, mpx2)
                let sY2 = max(mpy1, mpy2)
                paint.drawRect(color:plot.lineColor, width:plot.lineWidth, style:[], left:sX1, top:sY1, right:sX2, bottom:sY2)
                paint.drawText(text:String(abs(index2 - index1) + 1), color:chart.textColor, font:chart.font, x:sX1 + 2, y:sY1 + 2)
                var closeList = [Double]()
                for j in index1...index2{
                    closeList.append(chart.data[j].close)
                }
                let avgClose = avgValue(list:closeList)
                let closeY = getChartY(chart:chart, divIndex:0, value:avgClose)
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[5,5], x1:sX1, y1:closeY, x2:sX2, y2:closeY)
                let drawAvg = toFixed(value:avgClose, digit:chart.candleDigit)
                let tSize = paint.textSize(text:drawAvg, font:chart.font)
                paint.drawText(text:drawAvg, color:chart.textColor, font:chart.font, x:sX1 + 2, y:closeY - tSize.cy - 2)
            }else if plot.plotType == "TironeLevels" {
                let sX1 = min(mpx1, mpx2)
                let sY1 = min(mpy1, mpy2)
                let sX2 = max(mpx1, mpx2)
                let sY2 = max(mpy1, mpy2)
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:sX1, y1:sY1, x2:sX2, y2:sY1)
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:sX1, y1:sY2, x2:sX2, y2:sY2)
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:sX1 + (sX2 - sX1) / 2, y1:sY1, x2:sX1 + (sX2 - sX1) / 2, y2:sY2)
                let t2 = chart.nHighChart - (chart.nHighChart - chart.nLowChart) / 3, t3 = chart.nHighChart - (chart.nHighChart - chart.nLowChart) / 2, t4 = chart.nHighChart - 2 * (chart.nHighChart - chart.nLowChart) / 3
                var tList = [Double]()
                tList.append(t2)
                tList.append(t3)
                tList.append(t4)
                for j in 0...tList.count - 1{
                    let y = getChartY(chart:chart, divIndex:0, value:tList[j])
                    //画直线
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[5,5], x1:chart.leftVScaleWidth, y1:y, x2:chart.size.cx - chart.rightVScaleWidth, y2:y)
                    let str = toFixed(value:tList[j], digit:chart.candleDigit)
                    let tSize = paint.textSize(text:str, font:chart.font)
                    paint.drawText(text:str, color:chart.textColor, font:chart.font, x:chart.leftVScaleWidth + 2, y:y - tSize.cy - 2)
                }
            }else if plot.plotType == "QuadrantLines" {
                let sX1 = min(mpx1, mpx2)
                let sY1 = min(mpy1, mpy2)
                let sX2 = max(mpx1, mpx2)
                let sY2 = max(mpy1, mpy2)
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:sX1, y1:sY1, x2:sX2, y2:sY1)
                paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:sX1, y1:sY2, x2:sX2, y2:sY2)
                let t2 = chart.nHighChart - (chart.nHighChart - chart.nLowChart) / 4, t3 = chart.nHighChart - (chart.nHighChart - chart.nLowChart) / 2, t4 = chart.nHighChart - 3 * (chart.nHighChart - chart.nLowChart) / 4
                var tList = [Double]()
                tList.append(t2)
                tList.append(t3)
                tList.append(t4)
                for j in 0...tList.count - 1{
                    let y = getChartY(chart:chart, divIndex:0, value:tList[j])
                    //画直线
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:sX1, y1:y, x2:sX2, y2:y)
                }
            }else if plot.plotType == "GoldenRatio" {
                let sY1 = min(mpy1, mpy2)
                let sY2 = max(mpy1, mpy2)
                var ranges = [Double]()
                ranges.append(0)
                ranges.append(0.236)
                ranges.append(0.382)
                ranges.append(0.5)
                ranges.append(0.618)
                ranges.append(0.809)
                ranges.append(1)
                ranges.append(1.382)
                ranges.append(1.618)
                ranges.append(2)
                ranges.append(2.382)
                ranges.append(2.618)
                for j in 0...ranges.count - 1{
                    let newY = sY1 <= sY2 ? sY1 + (sY2 - sY1) * ranges[j] : sY2 + (sY1 - sY2) * (1 - ranges[j])
                    paint.drawLine(color:plot.lineColor, width:plot.lineWidth, style:[], x1:chart.leftVScaleWidth, y1:newY, x2:chart.size.cx - chart.rightVScaleWidth, y2:newY)
                    let newPoint = FCPoint(x:0, y:newY)
                    let value = getCandleDivValue(chart:chart, point:newPoint)
                    let str = toFixed(value:value, digit:chart.candleDigit)
                    let tSize = paint.textSize(text:str, font:chart.font)
                    paint.drawText(text:str, color:chart.textColor, font:chart.font, x:chart.leftVScaleWidth + 2, y:newY - tSize.cy - 2)
                }
            }
            else if plot.plotType == "ArrowSegment" {
                var arrowSize = 24.0
                var slopy = 0.0, cosy = 0.0, siny = 0.0
                slopy = atan2(mpy1 - mpy2, mpx1 - mpx2)
                cosy = cos(slopy)
                siny = sin(slopy)
                let ptPoint = FCPoint(x:0, y:0)
                ptPoint.x = mpx2
                ptPoint.y = mpy2
                var pts = [FCPoint]()
                pts.append(FCPoint(x:ptPoint.x, y:ptPoint.y))
                pts.append(FCPoint(x:ptPoint.x + (arrowSize * cosy - (arrowSize / 2.0 * siny) + 0.5), y:ptPoint.y + (arrowSize * siny + (arrowSize / 2.0 * cosy) + 0.5)))
                pts.append(FCPoint(x:ptPoint.x + (arrowSize * cosy + arrowSize / 2.0 * siny + 0.5), y:ptPoint.y - (arrowSize / 2.0 * cosy - arrowSize * siny + 0.5)))
                arrowSize = 20.0
                let ptPoint2 = FCPoint(x:0, y:0)
                ptPoint2.x = mpx2
                ptPoint2.y = mpy2
                var pts2 = [FCPoint]()
                pts2.append(FCPoint(x:ptPoint2.x, y:ptPoint2.y))
                pts2.append(FCPoint(x:ptPoint2.x + (arrowSize * cosy - (arrowSize / 2.0 * siny) + 0.5), y:ptPoint2.y + (arrowSize * siny + (arrowSize / 2.0 * cosy) + 0.5)))
                pts2.append(FCPoint(x:ptPoint2.x + (arrowSize * cosy + arrowSize / 2.0 * siny + 0.5), y:ptPoint2.y - (arrowSize / 2.0 * cosy - arrowSize * siny + 0.5)))
                lineXY(chart:chart, x1:pts2[1].x, y1:pts2[1].y, x2:pts2[2].x, y2:pts2[2].y, oX:0, oY:0)
                var newX1 = 0.0, newY1 = 0.0, newX2 = 0.0, newY2 = 0.0
                if pts2[1].x > pts2[2].x {
                    newX1 = pts2[2].x + (pts2[1].x - pts2[2].x) / 3
                    newX2 = pts2[2].x + (pts2[1].x - pts2[2].x) * 2 / 3
                } else {
                    newX1 = pts2[1].x + (pts2[2].x - pts2[1].x) / 3
                    newX2 = pts2[1].x + (pts2[2].x - pts2[1].x) * 2 / 3
                }
                if chart.kChart == 0 && chart.bChart == 0 {
                    if pts2[1].y > pts2[2].y {
                        newY1 = pts2[2].y + (pts2[1].y - pts2[2].y) / 3
                        newY2 = pts2[2].y + (pts2[1].y - pts2[2].y) * 2 / 3
                    } else {
                        newY1 = pts2[1].y + (pts2[2].y - pts2[1].y) / 3
                        newY2 = pts2[1].y + (pts2[2].y - pts2[1].y) * 2 / 3
                    }
                } else {
                    newY1 = (chart.kChart * newX1) + chart.bChart
                    newY2 = (chart.kChart * newX2) + chart.bChart
                }
                let p2 = FCPoint(x:newX1, y:newY1)
                pts2[1] = p2
                let p3 = FCPoint(x:newX2, y:newY2)
                pts2[2] = p3
                var drawPoints = [FCPoint]()
                drawPoints.append(FCPoint(x:ptPoint.x, y:ptPoint.y))
                drawPoints.append(FCPoint(x:pts[1].x, y:pts[1].y))
                if mpy1 >= mpy2 {
                    drawPoints.append(FCPoint(x:pts2[1].x, y:pts2[1].y))
                } else {
                    drawPoints.append(FCPoint(x:pts2[2].x, y:pts2[2].y))
                }
                drawPoints.append(FCPoint(x:mpx1, y:mpy1))
                if mpy1 >= mpy2 {
                    drawPoints.append(FCPoint(x:pts2[2].x, y:pts2[2].y))
                } else {
                    drawPoints.append(FCPoint(x:pts2[1].x, y:pts2[1].y))
                }
                drawPoints.append(FCPoint(x:pts[2].x, y:pts[2].y))
                paint.beginPath()
                for j in 0...5{
                    if j > 0 {
                        paint.addLine(x1:drawPoints[j - 1].x, y1:drawPoints[j - 1].y, x2:drawPoints[j].x, y2:drawPoints[j].y)
                    }
                }
                paint.fillPath(color:plot.lineColor)
                paint.closePath()
            }
        }
        paint.restore()
    }
}

/*
* 绘制图表
* chart:图表
* paint:绘图对象
* clipRect:裁剪区域
*/
func drawChartStock(chart:FCChart, paint:FCPaint, clipRect:FCRect) {
    let candleHeight = getCandleDivHeight(chart:chart)
    let volHeight = getVolDivHeight(chart:chart)
    let indHeight = getIndDivHeight(chart:chart)
    let isTrend = chart.cycle == "trend"
    var cWidth = Double(Int((chart.hScalePixel - 3) / 2))
    if cWidth < 0 {
        cWidth = 0
    }
    var lastValidIndex = chart.lastVisibleIndex
    if chart.lastValidIndex != -1{
        lastValidIndex = chart.lastValidIndex
    }
    if chart.data.count > 0 {
        let maxVisibleRecord = getChartMaxVisibleCount(chart:chart, hScalePixel:chart.hScalePixel, pureH:getChartWorkAreaWidth(chart:chart))
        paint.save()
        paint.setClip(left:chart.leftVScaleWidth, top:0, right:chart.size.cx - chart.rightVScaleWidth, bottom:candleHeight)
        if isTrend {
            paint.beginPath()
            var lastX = 0.0, lastY = 0.0
            for i in chart.firstVisibleIndex...lastValidIndex{
                let x = getChartX(chart:chart, index:i)
                let close = chart.data[i].close
                let closeY = getChartY(chart:chart, divIndex:0, value:close)
                if i > chart.firstVisibleIndex {
                    paint.addLine(x1:lastX, y1:lastY, x2:x, y2:closeY)
                }
                lastX = x
                lastY = closeY
            }
            paint.drawPath(color:chart.indicatorColors[7], width:chart.lineWidthChart, style:[])
            paint.closePath()
        }
        var hasMinTag = false, hasMaxTag = false
        for i in chart.firstVisibleIndex...lastValidIndex{
            let x = getChartX(chart:chart, index:i)
            let open = chart.data[i].open
            let close = chart.data[i].close
            let high = chart.data[i].high
            let low = chart.data[i].low
            let openY = getChartY(chart:chart, divIndex:0, value:open)
            let closeY = getChartY(chart:chart, divIndex:0, value:close)
            let highY = getChartY(chart:chart, divIndex:0, value:high)
            let lowY = getChartY(chart:chart, divIndex:0, value:low)
            if close >= open {
                if isTrend {
                } else {
                    paint.drawLine(color:chart.upColor, width:chart.lineWidthChart, style:[], x1:x, y1:highY, x2:x, y2:lowY)
                    if cWidth > 0 {
                        if close == open {
                            paint.drawLine(color:chart.upColor, width:chart.lineWidthChart, style:[], x1:x - cWidth, y1:closeY, x2:x + cWidth, y2:closeY)
                        }
                        else {
                            if chart.candleStyle == "rect2"{
                                paint.fillRect(color:chart.backColor, left:x - cWidth, top:closeY, right:x + cWidth, bottom:openY)
                                paint.drawRect(color: chart.upColor, width: 1, style: [], left: x - cWidth, top: closeY, right: x + cWidth, bottom: openY)
                            }else{
                                paint.fillRect(color:chart.upColor, left:x - cWidth, top:closeY, right:x + cWidth, bottom:openY)
                            }
                        }
                    }
                }
            } else {
                if isTrend {
                } else {
                    paint.drawLine(color:chart.downColor, width:chart.lineWidthChart, style:[], x1:x, y1:highY, x2:x, y2:lowY)
                    if cWidth > 0 {
                        paint.fillRect(color:chart.downColor, left:x - cWidth, top:openY, right:x + cWidth, bottom:closeY)
                    }
                }
            }
            if chart.selectShape == "CANDLE" {
                var kPInterval = Int(maxVisibleRecord / 30)
                if kPInterval < 2 {
                    kPInterval = 3
                }
                if i % kPInterval == 0 {
                    if isTrend {
                    } else {
                        paint.fillRect(color:chart.indicatorColors[0], left:x - 3, top:closeY - 3, right:x + 3, bottom:closeY + 3)
                    }
                }
            }
            if !isTrend {
                if !hasMaxTag {
                    if high == chart.candleMax {
                        let tag = toFixed(value:high, digit:chart.candleDigit)
                        let tSize = paint.textSize(text:tag, font:chart.font)
                        paint.drawText(text:tag, color:chart.textColor, font:chart.font, x:x - tSize.cx / 2, y:highY - tSize.cy / 2 - 2)
                        hasMaxTag = true
                    }
                }
                if !hasMinTag {
                    if low == chart.candleMin {
                        let tag = toFixed(value:low, digit:chart.candleDigit)
                        let tSize = paint.textSize(text:tag, font:chart.font)
                        paint.drawText(text:tag, color:chart.textColor, font:chart.font, x:x - tSize.cx / 2, y:lowY + 2 + tSize.cy / 2)
                        hasMinTag = true
                    }
                }
            }
        }
        paint.restore()
        for i in chart.firstVisibleIndex...lastValidIndex{
            let x = getChartX(chart:chart, index:i)
            let open = chart.data[i].open
            let close = chart.data[i].close
            var volY = 0.0
            var zeroY = 0.0
            if volHeight > 0 {
                let volume = chart.data[i].volume
                volY = getChartY(chart:chart, divIndex:1, value:volume)
                zeroY = getChartY(chart:chart, divIndex:1, value:0)
            }
            if close >= open {
                if isTrend {
                    if volHeight > 0 {
                        paint.drawLine(color:chart.indicatorColors[6], width:chart.lineWidthChart, style:[], x1:x, y1:volY, x2:x, y2:zeroY)
                    }
                } else {
                    if cWidth > 0 {
                        if volHeight > 0 {
                            if chart.barStyle == "rect2"{
                                paint.fillRect(color:chart.backColor, left:x - cWidth, top:volY, right:x + cWidth, bottom:zeroY)
                                paint.drawRect(color: chart.upColor, width: 1, style: [], left:x - cWidth, top:volY, right:x + cWidth, bottom:zeroY)
                            }else{
                                paint.fillRect(color:chart.upColor, left:x - cWidth, top:volY, right:x + cWidth, bottom:zeroY)
                            }
                        }
                    } else {
                        if volHeight > 0 {
                            paint.drawLine(color:chart.upColor, width:chart.lineWidthChart, style:[], x1:x - cWidth, y1:volY, x2:x + cWidth, y2:zeroY)
                        }
                    }
                }
            } else {
                if isTrend {
                    if volHeight > 0 {
                        paint.drawLine(color:chart.indicatorColors[6], width:chart.lineWidthChart, style:[], x1:x, y1:volY, x2:x, y2:zeroY)
                    }
                } else {
                    if cWidth > 0 {
                        if volHeight > 0 {
                            paint.fillRect(color:chart.downColor, left:x - cWidth, top:volY, right:x + cWidth, bottom:zeroY)
                        }
                    } else {
                        if volHeight > 0 {
                            paint.drawLine(color:chart.downColor, width:chart.lineWidthChart, style:[], x1:x - cWidth, y1:volY, x2:x + cWidth, y2:zeroY)
                        }
                    }
                }
            }
            if chart.selectShape == "VOL" {
                var kPInterval = Int(maxVisibleRecord / 30)
                if kPInterval < 2 {
                    kPInterval = 3
                }
                if i % kPInterval == 0 {
                    paint.fillRect(color:chart.indicatorColors[0], left:x - 3, top:volY - 3, right:x + 3, bottom:volY + 3)
                }
            }
        }
        if !isTrend {
            paint.save()
            paint.setClip(left:chart.leftVScaleWidth, top:0, right:chart.size.cx - chart.rightVScaleWidth, bottom:candleHeight)
            if chart.mainIndicator == "BOLL" {
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:0, datas:chart.bollMid, color:chart.indicatorColors[0], selected:(chart.selectShape == chart.mainIndicator && chart.selectShapeEx == "MID") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:0, datas:chart.bollUp, color:chart.indicatorColors[1], selected:(chart.selectShape == chart.mainIndicator && chart.selectShapeEx == "UP") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:0, datas:chart.bollDown, color:chart.indicatorColors[2], selected:(chart.selectShape == chart.mainIndicator && chart.selectShapeEx == "DOWN") ? true : false)
            } else if chart.mainIndicator == "MA" {
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:0, datas:chart.ma5, color:chart.indicatorColors[0], selected: (chart.selectShape == chart.mainIndicator && chart.selectShapeEx == "5") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:0, datas:chart.ma10, color:chart.indicatorColors[1], selected:(chart.selectShape == chart.mainIndicator && chart.selectShapeEx == "10") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:0, datas:chart.ma20, color:chart.indicatorColors[2], selected:(chart.selectShape == chart.mainIndicator && chart.selectShapeEx == "20") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:0, datas:chart.ma30, color:chart.indicatorColors[5], selected:(chart.selectShape == chart.mainIndicator && chart.selectShapeEx == "30") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:0, datas:chart.ma120, color:chart.indicatorColors[4], selected:(chart.selectShape == chart.mainIndicator && chart.selectShapeEx == "120") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:0, datas:chart.ma250, color:chart.indicatorColors[3], selected:(chart.selectShape == chart.mainIndicator && chart.selectShapeEx == "250") ? true : false)
            }
            paint.restore()
        }
        if indHeight > 0 {
            if chart.showIndicator == "MACD" {
                let zeroY = getChartY(chart:chart, divIndex:2, value:0)
                paint.drawLine(color:chart.indicatorColors[4], width:chart.lineWidthChart, style:[], x1:chart.leftVScaleWidth, y1:zeroY, x2:getChartX(chart:chart, index:chart.lastVisibleIndex), y2:zeroY)
                for i in chart.firstVisibleIndex...lastValidIndex{
                    let x = getChartX(chart:chart, index:i)
                    let macd = chart.allmacdarr[i]
                    let macdY = getChartY(chart:chart, divIndex:2, value:macd)
                    if macdY < zeroY {
                        paint.drawLine(color:chart.indicatorColors[3], width:chart.lineWidthChart, style:[], x1:x, y1:macdY, x2:x, y2:zeroY)
                    } else {
                        paint.drawLine(color:chart.indicatorColors[4], width:chart.lineWidthChart, style:[], x1:x, y1:macdY, x2:x, y2:zeroY)
                    }
                    if chart.selectShape == chart.showIndicator && chart.selectShapeEx == "MACD" {
                        var kPInterval = Int(maxVisibleRecord / 30)
                        if (kPInterval < 2) {
                            kPInterval = 3
                        }
                        if i % kPInterval == 0 {
                            paint.fillRect(color:chart.indicatorColors[4], left:x - 3, top:macdY - 3, right:x + 3, bottom:macdY + 3)
                        }
                    }
                }
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.alldifarr, color:chart.indicatorColors[0], selected: (chart.selectShape == chart.showIndicator && chart.selectShapeEx == "DIF") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.alldeaarr, color:chart.indicatorColors[1], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "DEA") ? true : false)
            } else if chart.showIndicator == "KDJ" {
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.kdjK, color:chart.indicatorColors[0], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "K") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.kdjD, color:chart.indicatorColors[1], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "D") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.kdjJ, color:chart.indicatorColors[2], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "J") ? true : false)
            } else if chart.showIndicator == "RSI" {
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.rsi1, color:chart.indicatorColors[5], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "6") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.rsi2, color:chart.indicatorColors[1], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "12") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.rsi3, color:chart.indicatorColors[2], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "24") ? true : false)
            }
            else if chart.showIndicator == "BIAS" {
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.bias1, color:chart.indicatorColors[5], selected: (chart.selectShape == chart.showIndicator && chart.selectShapeEx == "1") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.bias2, color:chart.indicatorColors[1], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "2") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.bias3, color:chart.indicatorColors[2], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "3") ? true : false)
            }
            else if chart.showIndicator == "ROC" {
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.roc, color:chart.indicatorColors[0], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "ROC") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.rocMa, color:chart.indicatorColors[1], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "ROCMA") ? true : false)
            } else if chart.showIndicator == "WR" {
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.wr1, color:chart.indicatorColors[0], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "1") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.wr2, color:chart.indicatorColors[1], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "2") ? true : false)
            } else if chart.showIndicator == "CCI" {
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.cci, color:chart.indicatorColors[0], selected:(chart.selectShape == chart.showIndicator) ? true : false)
            } else if chart.showIndicator == "BBI" {
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.bbi, color:chart.indicatorColors[0], selected:(chart.selectShape == chart.showIndicator) ? true : false)
            } else if chart.showIndicator == "TRIX" {
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.trix, color:chart.indicatorColors[0], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "TRIX") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.trixMa, color:chart.indicatorColors[1], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "TRIXMA") ? true : false)
            } else if chart.showIndicator == "DMA" {
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.dma1, color:chart.indicatorColors[0], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "DIF") ? true : false)
                drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:2, datas:chart.dma2, color:chart.indicatorColors[1], selected:(chart.selectShape == chart.showIndicator && chart.selectShapeEx == "DIFMA") ? true : false)
            }
        }
    }
    //绘制扩展线条
    if chart.shapes.count > 0 {
        for i in 0...chart.shapes.count - 1{
            let shape = chart.shapes[i]
            if shape.shapeType == "bar" {
                for j in chart.firstVisibleIndex...lastValidIndex {
                    if shape.showHideDatas.count > j && String(shape.showHideDatas[j]) == "0" {
                        continue
                    }
                    let x = getChartX(chart:chart, index:j)
                    var y1 = 0.0
                    if shape.leftOrRight {
                        y1 = getChartY(chart:chart, divIndex:shape.divIndex, value:shape.datas[j])
                    } else {
                        y1 = getChartYInRight(chart:chart, divIndex:shape.divIndex, value:shape.datas[j])
                    }
                    if shape.style != "2color" {
                        var y2 = 0.0
                        if shape.leftOrRight {
                            y2 = getChartY(chart:chart, divIndex:shape.divIndex, value:shape.datas2[j])
                        } else {
                            y2 = getChartYInRight(chart:chart, divIndex:shape.divIndex, value:shape.datas2[j])
                        }
                        if y1 >= y2 {
                            paint.fillRect(color:shape.color, left:x - cWidth, top:y2, right:x + cWidth, bottom:y1)
                        }
                        else {
                            paint.fillRect(color:shape.color, left:x - cWidth, top:y1, right:x + cWidth, bottom:y2)
                        }
                    } else {
                        var y2 = 0.0
                        if shape.leftOrRight {
                            y2 = getChartY(chart:chart, divIndex:shape.divIndex, value:0)
                        } else {
                            y2 = getChartYInRight(chart:chart, divIndex:shape.divIndex, value:0)
                        }
                        if y1 >= y2 {
                            paint.drawLine(color:shape.color2, width:1, style:[], x1:x, y1:y1, x2:x, y2:y2)
                        }
                        else {
                            paint.drawLine(color:shape.color, width:1, style:[], x1:x, y1:y1, x2:x, y2:y2)
                        }
                        if j == lastValidIndex {
                            paint.drawLine(color:shape.color2, width:1, style:[], x1:chart.leftVScaleWidth, y1:y2, x2:chart.size.cx - chart.rightVScaleWidth, y2:y2)
                        }
                    }
                }
            }
            else if shape.shapeType == "text" {
                for j in chart.firstVisibleIndex...lastValidIndex {
                    let x = getChartX(chart:chart, index:j)
                    if shape.datas[j] != 0 {
                        var y1 = 0.0
                        if shape.leftOrRight {
                            y1 = getChartY(chart:chart, divIndex:shape.divIndex, value:shape.value)
                        } else {
                            y1 = getChartYInRight(chart:chart, divIndex:shape.divIndex, value:shape.value)
                        }
                        let drawText = shape.text
                        let tSize = paint.textSize(text:drawText, font:"Default,14")
                        paint.drawText(text:drawText, color:shape.color, font:"Default,14", x:x - tSize.cx / 2, y:y1 - tSize.cy / 2)
                    }
                }
            }
            else {
                if shape.leftOrRight {
                    drawChartLines(chart:chart, paint:paint, clipRect:clipRect, divIndex:shape.divIndex, datas:shape.datas, color:shape.color, selected:(chart.selectShape == shape.shapeName) ? true : false)
                } else {
                    drawChartLinesInRight(chart:chart, paint:paint, clipRect:clipRect, divIndex:shape.divIndex, datas:shape.datas, color:shape.color, selected:(chart.selectShape == shape.shapeName) ? true : false)
                }
            }
        }
    }
}

/*
* 获取数据
* chart:图表
*/
func calcChartIndicator(chart:FCChart) {
    clearDataArr(chart:chart)
    if chart.data.count > 0{
        var closeArr = [Double]()
        var highArr = [Double]()
        var lowArr = [Double]()
        if chart.data.count > 0 {
            for i in 0...chart.data.count - 1 {
                closeArr.append(chart.data[i].close)
                highArr.append(chart.data[i].high)
                lowArr.append(chart.data[i].low)
            }
        }
        chart.closeArr = closeArr
        if chart.mainIndicator == "BOLL" {
            getBollData(ticks:closeArr, maDays:20, ups:&chart.bollUp, mas:&chart.bollMid, lows:&chart.bollDown)
        } else if chart.mainIndicator == "MA" {
            chart.ma5 = maValue(ticks:closeArr, days:5)
            chart.ma10 = maValue(ticks:closeArr, days:10)
            chart.ma20 = maValue(ticks:closeArr, days:20)
            chart.ma30 = maValue(ticks:closeArr, days:30)
            chart.ma120 = maValue(ticks:closeArr, days:120)
            chart.ma250 = maValue(ticks:closeArr, days:250)
        }
        if chart.showIndicator == "BIAS" {
            getBIASData(ticks:closeArr, n1:6, n2:12, n3:24, bias1Arr:&chart.bias1, bias2Arr:&chart.bias2, bias3Arr:&chart.bias3)
        }
        else if chart.showIndicator == "DMA"{
            getDMAData(ticks:closeArr, n1:10, n2:50, difArr:&chart.dma1, difmaArr:&chart.dma2)
        }
        else if chart.showIndicator == "BBI"{
            getBBIData(ticks:closeArr, n1:3, n2:6, n3:12, n4:24, bbiArr:&chart.bbi)
        }
        else if chart.showIndicator == "RSI"{
            getRSIData(ticks:closeArr, n1:6, n2:12, n3:24, rsi1:&chart.rsi1, rsi2:&chart.rsi2, rsi3:&chart.rsi3)
        }
        else if chart.showIndicator == "ROC"{
            getRocData(ticks:closeArr, n:12, m:6, roc:&chart.roc, maroc:&chart.rocMa)
        }
        else if chart.showIndicator == "TRIX"{
            getTRIXData(ticks:closeArr, m:9, trixArr:&chart.trix, matrixArr:&chart.trixMa)
        }
        else if chart.showIndicator == "KDJ"{
            getKDJData(highArr:highArr, lowArr:lowArr, closeArr:closeArr, n:9, m1:3, m2:3, ks:&chart.kdjK, ds:&chart.kdjD, js:&chart.kdjJ)
        }
        else if chart.showIndicator == "WR"{
            getWRData(highArr:highArr, lowArr:lowArr, closeArr:closeArr, n1:5, n2:10, wr1Arr:&chart.wr1, wr2Arr:&chart.wr2)
        }
        else if chart.showIndicator == "CCI"{
            getCCIData(highArr:highArr, lowArr:lowArr, closeArr:closeArr, n:14, cciArr:&chart.cci)
        }else if chart.showIndicator == "MACD" {
            //缓存MACD数据
            chart.allema12.append(closeArr[0])
            chart.allema26.append(closeArr[0])
            chart.alldeaarr.append(0)
            for i in 1...closeArr.count - 1{
                chart.allema12.append(getEMA(n:12, value:closeArr[i], lastEMA:chart.allema12[i - 1]))
                chart.allema26.append(getEMA(n:26, value:closeArr[i], lastEMA:chart.allema26[i - 1]))
            }
            chart.alldifarr = getDIF(close12:chart.allema12, close26:chart.allema26)
            for i in 1...chart.alldifarr.count - 1{
                chart.alldeaarr.append(chart.alldeaarr[i - 1] * 8 / 10 + chart.alldifarr[i] * 2 / 10)
            }
            chart.allmacdarr = getMACD(dif:chart.alldifarr, dea:chart.alldeaarr)
        }
    }
    if chart.hasCalculateChartMaxMinEvent{
        chart.onCalculateChartMaxMin(chart)
    }
    else if chart.getPaint().hasCalculateChartMaxMinEvent{
        chart.getPaint().onCalculateChartMaxMin(chart)
    }else{
        calculateChartMaxMin(chart:chart)
    }
}

/*
* 计算EMA
* n:周期
* value:当前数据
* lastEMA:上期数据
*/
func getEMA(n:Int, value:Double, lastEMA:Double)->Double {
    return (value * 2.0 + lastEMA * Double(n - 1)) / Double(n + 1)
}

/*
* 计算MACD
* dif:DIF数据
* dea:DEA数据
*/
func getMACD(dif:[Double], dea:[Double])->[Double] {
    var result = [Double]()
    for i in 0...dif.count - 1{
        result.append((dif[i] - dea[i]) * 2)
    }
    return result
}

/*
* 计算DIF
* close12:12日数据
* close26:26日数据
*/
func getDIF(close12:[Double], close26:[Double]) ->[Double] {
    var result = [Double]()
    for i in 0...close12.count - 1 {
        result.append(close12[i] - close26[i])
    }
    return result
}

/*
* 清除缓存数据方法
* chart:图表
*/
func clearDataArr(chart:FCChart) {
    chart.allema12 = [Double]()
    chart.allema26 = [Double]()
    chart.alldifarr = [Double]()
    chart.alldeaarr = [Double]()
    chart.allmacdarr = [Double]()
    chart.bollUp = [Double]()
    chart.bollDown = [Double]()
    chart.bollMid = [Double]()
    chart.bias1 = [Double]()
    chart.bias2 = [Double]()
    chart.bias3 = [Double]()
    chart.kdjK = [Double]()
    chart.kdjD = [Double]()
    chart.kdjJ = [Double]()
    chart.rsi1 = [Double]()
    chart.rsi2 = [Double]()
    chart.rsi3 = [Double]()
    chart.roc = [Double]()
    chart.rocMa = [Double]()
    chart.wr1 = [Double]()
    chart.wr2 = [Double]()
    chart.cci = [Double]()
    chart.bbi = [Double]()
    chart.trix = [Double]()
    chart.trixMa = [Double]()
    chart.dma1 = [Double]()
    chart.dma2 = [Double]()
    chart.ma5 = [Double]()
    chart.ma10 = [Double]()
    chart.ma20 = [Double]()
    chart.ma30 = [Double]()
    chart.ma120 = [Double]()
    chart.ma250 = [Double]()
}

/*
* 判断是否选中线条
* chart:图表
* mp:坐标
* divIndex:层索引
* datas:数据
* curIndex:当前索引
*/
func selectLines(chart:FCChart, mp:FCPoint, divIndex:Int, datas:[Double], curIndex:Int)->Bool{
    if datas.count > 0 {
        let topY = getChartY(chart:chart, divIndex:divIndex, value:datas[curIndex])
        if chart.hScalePixel <= 1 {
            if mp.y >= topY - 8 && mp.y <= topY + 8 {
                return true
            }
        } else {
            let index = curIndex
            let scaleX = getChartX(chart:chart, index:index)
            var judgeTop:Double = 0
            var judgeScaleX = scaleX
            if mp.x >= scaleX {
                let leftIndex = curIndex + 1
                if curIndex < chart.lastVisibleIndex {
                    let rightValue = datas[leftIndex]
                    judgeTop = getChartY(chart:chart, divIndex:divIndex, value:rightValue)
                }
                else {
                    judgeTop = topY
                }
            }
            else {
                judgeScaleX = scaleX - chart.hScalePixel
                let rightIndex = curIndex - 1
                if curIndex > 0 {
                    let leftValue = datas[rightIndex]
                    judgeTop = getChartY(chart:chart, divIndex:divIndex, value:leftValue)
                } else {
                    judgeTop = topY
                }
            }
            let lineWidth:Double = 4
            var judgeX:Double = 0
            var judgeY:Double = 0
            var judgeW:Double = 0
            var judgeH:Double = 0
            if judgeTop >= topY {
                judgeX = judgeScaleX
                judgeY = topY - 2 - lineWidth
                judgeW = chart.hScalePixel
                judgeH = judgeTop - topY + lineWidth < 4 ? 4 : judgeTop - topY + 4 + lineWidth
            }
            else {
                judgeX = judgeScaleX
                judgeY = judgeTop - 2 - lineWidth / 2
                judgeW = chart.hScalePixel
                judgeH = topY - judgeTop + lineWidth < 4 ? 4 : topY - judgeTop + 4 + lineWidth
            }

            if mp.x >= judgeX && mp.x <= judgeX + judgeW && mp.y >= judgeY && mp.y <= judgeY + judgeH {

                return true
            }
        }
    }
    return false
}

/*
* 判断是否在右轴选中线条
* chart:图表
* mp:坐标
* divIndex:层索引
* datas:数据
* curIndex:当前索引
*/
func selectLinesInRight(chart:FCChart, mp:FCPoint, divIndex:Int, datas:[Double], curIndex:Int)->Bool{
    if datas.count > 0 {
        let topY = getChartYInRight(chart:chart, divIndex:divIndex, value:datas[curIndex])
        if chart.hScalePixel <= 1 {
            if mp.y >= topY - 8 && mp.y <= topY + 8 {
                return true
            }
        } else {
            let index = curIndex
            let scaleX = getChartX(chart:chart, index:index)
            var judgeTop:Double = 0
            var judgeScaleX = scaleX
            if mp.x >= scaleX {
                let leftIndex = curIndex + 1
                if curIndex < chart.lastVisibleIndex {
                    let rightValue = datas[leftIndex]
                    judgeTop = getChartYInRight(chart:chart, divIndex:divIndex, value:rightValue)
                }
                else {
                    judgeTop = topY
                }
            }
            else {
                judgeScaleX = scaleX - chart.hScalePixel
                let rightIndex = curIndex - 1
                if curIndex > 0 {
                    let leftValue = datas[rightIndex]
                    judgeTop = getChartYInRight(chart:chart, divIndex:divIndex, value:leftValue)
                } else {
                    judgeTop = topY
                }
            }
            let lineWidth:Double = 4
            var judgeX:Double = 0
            var judgeY:Double = 0
            var judgeW:Double = 0
            var judgeH:Double = 0
            if judgeTop >= topY {
                judgeX = judgeScaleX
                judgeY = topY - 2 - lineWidth
                judgeW = chart.hScalePixel
                judgeH = judgeTop - topY + lineWidth < 4 ? 4 : judgeTop - topY + 4 + lineWidth
            }
            else {
                judgeX = judgeScaleX
                judgeY = judgeTop - 2 - lineWidth / 2
                judgeW = chart.hScalePixel
                judgeH = topY - judgeTop + lineWidth < 4 ? 4 : topY - judgeTop + 4 + lineWidth
            }

            if mp.x >= judgeX && mp.x <= judgeX + judgeW && mp.y >= judgeY && mp.y <= judgeY + judgeH {

                return true
            }
        }
    }
    return false
}

/*
* 判断是否选中图形
* chart:图表
* mp:坐标
*/
func selectShape(chart:FCChart, mp:FCPoint) {
    chart.selectShape = ""
    chart.selectShapeEx = ""
    let candleHeight = getCandleDivHeight(chart:chart)
    let volHeight = getVolDivHeight(chart:chart)
    let indHeight = getIndDivHeight(chart:chart)
    let index = getChartIndex(chart:chart, mp:mp)
    if mp.y >= candleHeight + volHeight && mp.y <= candleHeight + volHeight + indHeight {
        if chart.showIndicator == "MACD" {
            if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.allmacdarr, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "MACD"
            }
            if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.alldifarr, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "DIF"
            }
            else if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.alldeaarr, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "DEA"
            }
        } else if chart.showIndicator == "KDJ" {
            if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.kdjK, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "K"
            }
            else if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.kdjD, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "D"
            } else if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.kdjJ, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "J"
            }
        } else if chart.showIndicator == "RSI" {
            if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.rsi1, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "6"
            }
            else if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.rsi2, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "12"
            } else if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.rsi3, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "24"
            }
        }
        else if chart.showIndicator == "BIAS" {
            if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.bias1, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "1"
            }
            else if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.bias2, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "2"
            } else if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.bias3, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "3"
            }
        }
        else if chart.showIndicator == "ROC" {
            if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.roc, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "ROC"
            }
            else if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.rocMa, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "ROCMA"
            }
        } else if chart.showIndicator == "WR" {
            if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.wr1, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "1"
            }
            else if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.wr2, curIndex:index) {
                chart.selectShape = "WR"
                chart.selectShapeEx = "2"
            }
        } else if chart.showIndicator == "CCI" {
            if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.cci, curIndex:index) {
                chart.selectShape = chart.showIndicator
            }
        } else if chart.showIndicator == "BBI" {
            if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.bbi, curIndex:index) {
                chart.selectShape = chart.showIndicator
            }
        } else if chart.showIndicator == "TRIX" {
            if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.trix, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "TRIX"
            }
            else if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.trixMa, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "TRIXMA"
            }
        } else if chart.showIndicator == "DMA" {
            if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.dma1, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "DIF"
            }
            else if selectLines(chart:chart, mp:mp, divIndex:2, datas:chart.dma2, curIndex:index) {
                chart.selectShape = chart.showIndicator
                chart.selectShapeEx = "DIFMA"
            }
        }
    }
    else if mp.y >= candleHeight && mp.y <= candleHeight + volHeight {
        let volY = getChartY(chart:chart, divIndex:1, value:chart.data[index].volume)
        let zeroY = getChartY(chart:chart, divIndex:1, value:0)
        if mp.y >= min(volY, zeroY) && mp.y <= max(volY, zeroY) {
            chart.selectShape = "VOL"
        }
    }
    else if mp.y >= 0 && mp.y <= candleHeight {
        let isTrend = chart.cycle == "trend"
        if !isTrend {
            if chart.mainIndicator == "BOLL" {
                if selectLines(chart:chart, mp:mp, divIndex:0, datas:chart.bollMid, curIndex:index) {
                    chart.selectShape = chart.mainIndicator
                    chart.selectShapeEx = "MID"
                }
                else if selectLines(chart:chart, mp:mp, divIndex:0, datas:chart.bollUp, curIndex:index) {
                    chart.selectShape = chart.mainIndicator
                    chart.selectShapeEx = "UP"
                } else if selectLines(chart:chart, mp:mp, divIndex:0, datas:chart.bollDown, curIndex:index) {
                    chart.selectShape = chart.mainIndicator
                    chart.selectShapeEx = "DOWN"
                }
            } else if chart.mainIndicator == "MA" {
                if selectLines(chart:chart, mp:mp, divIndex:0, datas:chart.ma5, curIndex:index) {
                    chart.selectShape = chart.mainIndicator
                    chart.selectShapeEx = "5"
                }
                else if selectLines(chart:chart, mp:mp, divIndex:0, datas:chart.ma10, curIndex:index) {
                    chart.selectShape = chart.mainIndicator
                    chart.selectShapeEx = "10"
                }
                else if selectLines(chart:chart, mp:mp, divIndex:0, datas:chart.ma20, curIndex:index) {
                    chart.selectShape = chart.mainIndicator
                    chart.selectShapeEx = "20"
                }
                else if selectLines(chart:chart, mp:mp, divIndex:0, datas:chart.ma30, curIndex:index) {
                    chart.selectShape = chart.mainIndicator
                    chart.selectShapeEx = "30"
                }
                else if selectLines(chart:chart, mp:mp, divIndex:0, datas:chart.ma120, curIndex:index) {
                    chart.selectShape = chart.mainIndicator
                    chart.selectShapeEx = "120"
                }
                else if selectLines(chart:chart, mp:mp, divIndex:0, datas:chart.ma250, curIndex:index) {
                    chart.selectShape = chart.mainIndicator
                    chart.selectShapeEx = "250"
                }
            }
        }
        if chart.selectShape == "" {
            let highY = getChartY(chart:chart, divIndex:0, value:chart.data[index].high)
            let lowY = getChartY(chart:chart, divIndex:0, value:chart.data[index].low)
            if isTrend {
                if selectLines(chart:chart, mp:mp, divIndex:0, datas:chart.closeArr, curIndex:index) {
                    chart.selectShape = "CANDLE"
                }
            }
            else {
                if mp.y >= min(lowY, highY) && mp.y <= max(lowY, highY) {
                    chart.selectShape = "CANDLE"
                }
            }
        }
    }
    if chart.shapes.count > 0 {
        for i in 0...chart.shapes.count - 1{
            let shape = chart.shapes[i]
            if shape.leftOrRight {
                if selectLines(chart:chart, mp:mp, divIndex:shape.divIndex, datas:shape.datas, curIndex:index) {
                    chart.selectShape = shape.shapeName
                    break
                }
            } else {
                if selectLinesInRight(chart:chart, mp:mp, divIndex:shape.divIndex, datas:shape.datas, curIndex:index) {
                    chart.selectShape = shape.shapeName
                    break
                }
            }
        }
    }
}

/*
 * 鼠标抬起方法
 * view:视图
 * mp:坐标
 * buttons:按钮
 * clicks:点击次数
 * delta:滚轮值
 */
func onMouseDownDefault(view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int){
    if view.hasMouseDownEvent{
        view.onMouseDown(view, mp, buttons, clicks, delta)
        return
    }
    var firstTouch = false
    var secondTouch = false
    let firstPoint = mp
    let secondPoint = mp
    if buttons == 1{
        firstTouch = true
    }
    else if buttons == 2{
        secondTouch = true
    }
    if view.viewType == "tree" {
        touchDownTree(tree:view as! FCTree, firstTouch:firstTouch, firstPoint:firstPoint, secondTouch:secondTouch, secondPoint:secondPoint, clicks:1)
    }
    else if view.viewType == "grid" {
        touchDownGrid(grid:view as! FCGrid, firstTouch:firstTouch, firstPoint:firstPoint, secondTouch:secondTouch, secondPoint:secondPoint, clicks:1)
    }
    else if view.viewType == "div" || view.viewType == "layout" || view.viewType == "menu" {
        touchDownDiv(div:view as! FCDiv, firstTouch:firstTouch, firstPoint:firstPoint, secondTouch:secondTouch, secondPoint:secondPoint, clicks:1)
    }
    else if view.viewType == "calendar" {
        clickCalendar(calendar: view as! FCCalendar, mp:firstPoint)
    }
    else if view.viewType == "button" {
        invalidateView(view:view)
    }else if view.viewType == "chart" {
        touchDownChart(chart:view as! FCChart, firstTouch:firstTouch, firstPoint:firstPoint, secondTouch:secondTouch, secondPoint:secondPoint)
    }
}

/*
 * 鼠标移动方法
 * view:视图
 * mp:坐标
 * buttons:按钮
 * clicks:点击次数
 * delta:滚轮值
 */
func onMouseMoveDefault(view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) {
    if view.hasMouseMoveEvent{
        view.onMouseMove(view, mp, buttons, clicks, delta)
        return
    }
    var firstTouch = false
    var secondTouch = false
    let firstPoint = mp
    let secondPoint = mp
    if buttons == 1{
        firstTouch = true
    }
    else if buttons == 2{
        secondTouch = true
    }
    if view.viewType == "tree" {
        touchMoveTree(tree:view as! FCTree, firstTouch:firstTouch, firstPoint:firstPoint, secondTouch:secondTouch, secondPoint:secondPoint)
        invalidateView(view:view)
    }
    else if view.viewType == "grid" {
        touchMoveGrid(grid:view as! FCGrid, firstTouch:firstTouch, firstPoint:firstPoint, secondTouch:secondTouch, secondPoint:secondPoint)
        invalidateView(view:view)
    }
    else if view.viewType == "div" || view.viewType == "layout" || view.viewType == "menu" {
        touchMoveDiv(div:view as! FCDiv, firstTouch:firstTouch, firstPoint:firstPoint, secondTouch:secondTouch, secondPoint:secondPoint)
        invalidateView(view:view)
    }
    else if view.viewType == "chart" {
        touchMoveChart(chart:view as! FCChart, firstTouch:firstTouch, firstPoint:firstPoint, secondTouch:secondTouch, secondPoint:secondPoint)
        invalidateView(view:view)
    }else if view.viewType == "menuitem" {
        touchMoveMenuItem(item:view as! FCMenuItem)
    }else{
        if view.allowDrag && view.getParent().isNotEmpty && view.getParent().viewType == "split" && (view.getParent() as! FCSplitLayoutDiv).getSplitter() == view{
            let splitLayoutDiv = view.getParent() as! FCSplitLayoutDiv
           if splitLayoutDiv.layoutStyle == "lefttoright" || splitLayoutDiv.layoutStyle == "righttoleft"{
                NSCursor.resizeLeftRight.set()
            }
            else{
                NSCursor.resizeUpDown.set()
            }
        }
        invalidateView(view:view)
    }
}

/*
* 触摸结束方法
* view:视图
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
*/
func onMouseUpDefault(view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) {
    if view.hasMouseUpEvent{
        view.onMouseUp(view, mp, buttons, clicks, delta)
        return
    }
    var firstTouch = false
    var secondTouch = false
    let firstPoint = mp
    let secondPoint = mp
    if buttons == 1{
        firstTouch = true
    }
    else if buttons == 2{
        secondTouch = true
    }
    if view.viewType == "tree" {
        touchUpTree(tree:view as! FCTree, firstTouch:firstTouch, firstPoint:firstPoint, secondTouch:secondTouch, secondPoint:secondPoint, clicks:1)
    }
    else if view.viewType == "grid" {
        touchUpGrid(grid:view as! FCGrid, firstTouch:firstTouch, firstPoint:firstPoint, secondTouch:secondTouch, secondPoint:secondPoint, clicks:1)
    }
    else if view.viewType == "div" || view.viewType == "layout" || view.viewType == "menu" {
        touchUpDiv(div:view as! FCDiv, firstTouch:firstTouch, firstPoint:firstPoint, secondTouch:secondTouch, secondPoint:secondPoint, clicks:1)
    }
    else if view.viewType == "chart" {
        let chart = view as! FCChart
        chart.firstTouchIndexCacheChart = -1
        chart.secondTouchIndexCacheChart = -1
    }
    invalidateView(view:view)
}

/*
 * 鼠标滚轮方法
 * view:视图
 * mp:坐标
 * buttons:按钮
 * clicks:点击次数
 * delta:滚轮值
 */
func onMouseWheelDefault(view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int)
{
    if view.hasMouseWheelEvent{
        view.onMouseWheel(view, mp, buttons, clicks, delta)
        return
    }
    if view.viewType == "grid"{
        touchWheelGrid(grid:view as! FCGrid, delta:delta)
        invalidateView(view:view)
    }
    else if view.viewType == "tree"{
        touchWheelTree(tree:view as! FCTree, delta:delta)
        invalidateView(view:view)
    }
    else if view.viewType == "div" || view.viewType == "layout" || view.viewType == "menu"{
        touchWheelDiv(div:view as! FCDiv, delta:delta)
        invalidateView(view:view)
    }
    else if view.viewType == "chart"{
        if delta > 0{
            zoomOutChart(chart:view as! FCChart)
        }
        else if delta < 0{
            zoomInChart(chart:view as! FCChart)
        }
        invalidateView(view:view)
    }
}

/*
 * 键盘按下方法
 * key:键盘值
 */
func onKeyDownDefault(view:FCView, value:Int)
{
    if view.hasKeyDownEvent{
        view.onKeyDown(view, value)
        return
    }
    if view.viewType == "chart"{
        if value == 38{
            zoomOutChart(chart:view as! FCChart)
        }
        else if value == 40{
            zoomInChart(chart:view as! FCChart)
        }
        invalidateView(view:view)
    }
}

/*
 * 键盘抬起方法
 * key:键盘值
 */
func onKeyUpDefault(view:FCView, value:Int)
{
    if view.hasKeyUpEvent{
        view.onKeyUp(view, value)
        return
    }
}

/*
* 点击方法
* view:视图
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
* clicks:点击次数
*/
func onClickDefault(view:FCView, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint, clicks:Int) {
    if view.hasClickEvent{
        view.onClick(view, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
        return
    }
    if view.viewType == "tabbutton" {
        let tabView = view.getParent() as! FCTabView
        if tabView.tabPages.count > 0{
            for i in 0...tabView.tabPages.count - 1{
                if tabView.tabPages[i].getHeaderButton() == view{
                    selectTabPage(tabView:tabView, tabPage:tabView.tabPages[i])
                    break
                }
            }
        }
        invalidateView(view:tabView)
    }
    else if view.viewType == "radiobutton" {
        clickRadioButton(radioButton:view as! FCRadioButton, mp:firstPoint)
        invalidate(paint:view.getPaint())
    }
    else if view.viewType == "checkbox" {
        clickCheckBox(checkBox:view as! FCCheckBox, mp:firstPoint)
        invalidateView(view:view.getParent())
    } else if view.viewType == "menuitem" {
        clickMenuItem(item:view as! FCMenuItem)
    } else if view.viewType == "combobox"{
        clickComboBox(comboBox:view as! FCComboBox)
    }
}

/*
* 重绘背景的实现方法
* view:视图
* paint:绘图对象
* clipRect:裁剪区域
*/
func onPaintDefault(view:FCView, paint:FCPaint, clipRect:FCRect) {
    if view.hasPaintEvent{
        view.onPaint(view, paint, clipRect)
        return
    }
    if view.viewType == "chart" {
        drawChart(chart:view as! FCChart, paint:paint, clipRect:clipRect)
    }
    else if view.viewType == "div" || view.viewType == "layout" || view.viewType == "tabpage" {
        drawDiv(div:view, paint:paint, clipRect:clipRect)
    }
    else if view.viewType == "grid" {
        drawDiv(div:view, paint:paint, clipRect:clipRect)
        drawGrid(grid:view as! FCGrid, paint:paint, clipRect:clipRect)
    }
    else if view.viewType == "tree" {
        drawDiv(div:view, paint:paint, clipRect:clipRect)
        drawTree(tree:view as! FCTree, paint:paint, clipRect:clipRect)
    }
    else if view.viewType == "calendar" {
        drawCalendar(calendar: view as! FCCalendar, paint:paint)
    }
    else if view.viewType == "label" {
        if view.textColor != "none" {
            let tSize = paint.textSize(text:view.text, font:view.font)
            paint.drawText(text:view.text, color:view.textColor, font:view.font, x:0, y:(view.size.cy - tSize.cy) / 2)
        }
    }
    else if view.viewType == "textbox" {
        drawDiv(div:view, paint:paint, clipRect:clipRect)
        if view.textColor != "none" {
            let tSize = paint.textSize(text:view.text, font:view.font)
            paint.drawText(text:view.text, color:view.textColor, font:view.font, x:0, y:(view.size.cy - tSize.cy) / 2)
        }
    }
    else if view.viewType == "radiobutton" {
        drawRadioButton(radioButton:view as! FCRadioButton, paint:paint, clipRect:clipRect)
    }
    else if view.viewType == "checkbox" {
        drawCheckBox(checkBox:view as! FCCheckBox, paint:paint, clipRect:clipRect)
    }else if view.viewType == "menuitem" {
        drawMenuItem(item:view as! FCMenuItem, paint:paint, clipRect:clipRect)
    } else if view.viewType == "combobox" {
        drawComboBox(comboBox: view as! FCComboBox, paint:paint, clipRect:clipRect)
    }
    else {
        drawButton(button:view, paint:paint, clipRect:clipRect)
    }
}

/*
* 重绘边框的实现方法
* view:视图
* paint:绘图对象
* clipRect:裁剪区域
*/
func onPaintBorderDefault(view:FCView, paint:FCPaint, clipRect:FCRect) {
    if view.hasPaintBorderEvent{
        view.onPaintBorder(view, paint, clipRect)
        return
    }
    if view.viewType == "grid" {
        drawGridScrollBar(grid:view as! FCGrid, paint:paint, clipRect:clipRect)
        drawDivBorder(div:view, paint:paint, clipRect:clipRect)
    }
    else if view.viewType == "tree" {
        drawTreeScrollBar(tree:view as! FCTree, paint:paint, clipRect:clipRect)
        drawDivBorder(div:view, paint:paint, clipRect:clipRect)
    }
    else if view.viewType == "div" || view.viewType == "layout" || view.viewType == "menu" {
        drawDivScrollBar(div:view as! FCDiv, paint:paint, clipRect:clipRect)
        drawDivBorder(div:view, paint:paint, clipRect:clipRect)
    }
    else if view.viewType == "tabpage" {
        drawDivBorder(div:view, paint:paint, clipRect:clipRect)
    }
    else if view.viewType == "tabview" {
        drawTabViewBorder(tabView:view as! FCTabView, paint:paint, clipRect:clipRect)
    } else if view.viewType == "textbox" {
        drawDivBorder(div:view, paint:paint, clipRect:clipRect)
    }
}

/*
 * xmlChar转成String
 */
func xmlCharToString(xmlChar: UnsafePointer<xmlChar>?) -> String? {
    guard let xmlChar = xmlChar else { return nil }
    return String(cString: xmlChar)
}

/*
* 设置属性
* view:视图
* node:xml节点
*/
func setAttributeDefault(view:FCView, node:xmlNodePtr){
    if view.getPaint().defaultUIStyle == "dark" {
        view.backColor = "rgb(0,0,0)"
        view.borderColor = "rgb(100,100,100)"
        view.textColor = "rgb(255,255,255)"
        view.scrollBarColor = "rgb(100,100,100)"
    } else if view.getPaint().defaultUIStyle == "light" {
        view.backColor = "rgb(255,255,255)"
        view.borderColor = "rgb(150,150,150)"
        view.textColor = "rgb(0,0,0)"
        view.scrollBarColor = "rgb(200,200,200)"
    }
    let attr = node.pointee.properties
    var attribute = attr
    while attribute != nil{
        let name = xmlCharToString(xmlChar:attribute?.pointee.name)
        let atrValueAtr = xmlGetProp(node, attribute?.pointee.name)
        let value = String(cString: atrValueAtr!)
        xmlFree(atrValueAtr)
        if name == "location" {
            let strs = value.split(separator: ",")
            let xStr = String(strs[0])
            let yStr = String(strs[1])
            if xStr.contains("%"){
                view.exAttributes["leftstr"] = xStr
            }
            else{
                view.location.x = Double(StringToFloat(str:xStr))
            }
            if yStr.contains("%"){
                view.exAttributes["topstr"] = yStr
            }else{
                view.location.y = Double(StringToFloat(str:yStr))
            }
        } else if name == "size" {
            let strs = value.split(separator: ",")
            let xStr = String(strs[0])
            let yStr = String(strs[1])
            if xStr.contains("%"){
                view.exAttributes["widthstr"] = xStr
            }
            else{
                view.size.cx = Double(StringToFloat(str:xStr))
            }
            if yStr.contains("%"){
                view.exAttributes["heightstr"] = yStr
            }else{
                view.size.cy = Double(StringToFloat(str:yStr))
            }
        } else if name == "text" {
            view.text = value
        } else if name == "backcolor" {
            let lowerStr = value.lowercased()
            if lowerStr.contains("rgb") {
                view.backColor = value
            } else {
                view.backColor = "none"
            }
        } else if name == "bordercolor" {
            let lowerStr = value.lowercased()
            if lowerStr.contains("rgb") {
                view.borderColor = value
            } else {
                view.borderColor = "none"
            }
        } else if name == "textcolor" {
            let lowerStr = value.lowercased()
            if lowerStr.contains("rgb") {
                view.textColor = value
            } else {
                view.textColor = "none"
            }
        } else if name == "layoutstyle" {
            if view is FCLayoutDiv{
                (view as! FCLayoutDiv).layoutStyle = value.lowercased()
            }else if view is FCSplitLayoutDiv{
                (view as! FCSplitLayoutDiv).layoutStyle = value.lowercased()
            }
        } else if name == "align" {
            view.align = value.lowercased()
        } else if name == "vertical-align" {
            view.verticalAlign = value.lowercased()
        } else if name == "dock" {
            view.dock = value.lowercased()
        } else if name == "font" {
            view.font = value
        } else if name == "headerheight" {
            if view is FCTree{
                (view as! FCTree).headerHeight = Double(StringToFloat(str:value))
            }else if view is FCGrid{
                (view as! FCGrid).headerHeight = Double(StringToFloat(str:value))
            }
        } else if name == "cornerradius" {
            view.cornerRadius = Double(StringToFloat(str:value))
        } else if name == "borderwidth" {
            view.borderWidth = Double(StringToFloat(str:value))
        } else if name == "splitmode" {
            if view is FCSplitLayoutDiv{
                (view as! FCSplitLayoutDiv).splitMode = value.lowercased()
            }
        }
        else if name == "autowrap" {
            if view is FCLayoutDiv{
                (view as! FCLayoutDiv).autoWrap = value.lowercased() == "true"
            }
        } else if name == "tabindex" {
            view.tabIndex = Int(StringToFloat(str: value))
        } else if name == "tabstop" {
            view.tabStop = value.lowercased() == "true"
        } else if name == "name" {
            view.viewName = value
        }else if name == "cursor" {
            view.cursor = value
        }else if name == "enabled" {
            view.enabled = value.lowercased() == "true"
        }  else if name == "showvscrollbar" {
            view.showVScrollBar = value.lowercased() == "true"
        } else if name == "showhscrollbar" {
            view.showHScrollBar = value.lowercased() == "true"
        } else if name == "visible" {
            view.visible = value.lowercased() == "true"
        } else if name == "displayoffset" {
            view.displayOffset = value.lowercased() == "true"
        } else if name == "checked" {
            if view is FCCheckBox{
                (view as! FCCheckBox).checked = value.lowercased() == "true"
            }else if view is FCCheckBox{
                (view as! FCCheckBox).checked = value.lowercased() == "true"
            }
        } else if name == "buttonsize" {
            let strs = value.split(separator: ",")
            if view is FCCheckBox{
                (view as! FCCheckBox).buttonSize = FCSize(cx:Double(StringToFloat(str:String(strs[0]))), cy:Double(StringToFloat(str:String(strs[1]))))
            }else if view is FCRadioButton{
                (view as! FCRadioButton).buttonSize = FCSize(cx:Double(StringToFloat(str:String(strs[0]))), cy:Double(StringToFloat(str:String(strs[1]))))
            }
        } else if name == "topmost" {
            view.topMost = value.lowercased() == "true"
        }  else if name == "groupname" {
            if view is FCRadioButton{
                (view as! FCRadioButton).groupName = value
            }
        } else if name == "allowdragscroll" {
            view.allowDragScroll = value.lowercased() == "true"
        } else if name == "allowpreviewsevent" {
            view.allowPreviewsEvent = value.lowercased() == "true"
        } else if name == "allowdrag" {
            view.allowDrag = value.lowercased() == "true"
        } else if name == "allowresize" {
            view.allowResize = value.lowercased() == "true"
        } else if name == "indent" {
            if view is FCTree{
                (view as! FCTree).indent = Double(StringToFloat(str:value))
            }
        } else if (name == "showcheckbox") {
            if view is FCTree{
                (view as! FCTree).showCheckBox = value.lowercased() == "true"
            }
        }else if name == "padding" {
            let strs = value.split(separator: ",")
            view.padding = FCPadding(left:Double(StringToFloat(str:String(strs[0]))), top:Double(StringToFloat(str:String(strs[1]))), right:Double(StringToFloat(str:String(strs[2]))), bottom:Double(StringToFloat(str:String(strs[3]))))
        } else if name == "margin" {
            let strs = value.split(separator: ",")
            view.margin = FCPadding(left:Double(StringToFloat(str:String(strs[0]))), top:Double(StringToFloat(str:String(strs[1]))), right:Double(StringToFloat(str:String(strs[2]))), bottom:Double(StringToFloat(str:String(strs[3]))))
        }else if name == "hoveredcolor" {
            let lowerStr = value.lowercased()
            if lowerStr.contains("rgb") {
                view.hoveredColor = value
            } else {
                view.hoveredColor = "none"
            }
        }else if name == "pushedcolor" {
            let lowerStr = value.lowercased()
            if lowerStr.contains("rgb") {
                view.pushedColor = value
            } else {
                view.pushedColor = "none"
            }
        } else if name == "layout" {
            if(view is FCTabView){
                (view as! FCTabView).layout = value
            }
        }else if name == "width" {
            if value.contains("%"){
                view.exAttributes["widthstr"] = value
            }else{
                view.size.cx = Double(StringToFloat(str:value))
            }
        }else if name == "height"{
            if value.contains("%"){
                view.exAttributes["heightstr"] = value
            }else{
                view.size.cy = Double(StringToFloat(str:value))
            }
        }else if name == "top"{
            if value.contains("%"){
                view.exAttributes["topstr"] = value
            }else{
                view.location.y = Double(StringToFloat(str:value))
            }
        }else if name == "left"{
            if value.contains("%"){
                view.exAttributes["leftstr"] = value
            }else{
                view.location.x = Double(StringToFloat(str:value))
            }
        }else{
            view.exAttributes[name!] = value
        }
        attribute = attribute?.pointee.next
    }
}

/*
* 读取Xml中的树节点
* tree 树
* parentNode 父节点
* xmlNode Xml节点
*/
func readTreeXmlNodeDefault(tree: FCTree, parentNode: FCTreeNode, xmlNode: xmlNodePtr) {
    let treeNode = FCTreeNode()
    let attr = xmlNode.pointee.properties
    var attribute = attr
    while attribute != nil{
        let atrName = xmlCharToString(xmlChar:attribute?.pointee.name)
        if atrName == "text"{
            let atrValueAtr = xmlGetProp(xmlNode, attribute?.pointee.name)
            treeNode.value = String(cString: atrValueAtr!)
            xmlFree(atrValueAtr)
            break
        }
        attribute = attribute?.pointee.next
    }
    appendTreeNode(tree: tree, node:treeNode, parentNode:parentNode)
    var child = xmlNode.pointee.children
    while child != nil{
        let nName = xmlCharToString(xmlChar:child?.pointee.name)
        if nName == "node"{
            readTreeXmlNodeDefault(tree:tree, parentNode:treeNode, xmlNode:child!)
        }
        child = child?.pointee.next
    }
}

/*
* 读取Xml
* paint 绘图对象
* node节点
* parent 父视图
*/
func readXmlNodeDefault(paint:FCPaint, node:xmlNodePtr, parent:FCView){
    var child = node.pointee.children
    while child != nil{
        let nName = xmlCharToString(xmlChar:child?.pointee.name)
        if nName != "text"{
            var view = FCView()
            view.isNotEmpty = false
            var viewType = ""
            let nodeName = nName?.lowercased()
            let attr = child?.pointee.properties
            if nodeName == "div" || nodeName == "view" {
                var attribute = attr
                while attribute != nil{
                    let atrName = xmlCharToString(xmlChar:attribute?.pointee.name)
                    if atrName == "type"{
                        let atrValueAtr = xmlGetProp(child, attribute?.pointee.name)
                        viewType = String(cString: atrValueAtr!)
                        xmlFree(atrValueAtr)
                        break
                    }
                    attribute = attribute?.pointee.next
                }
                if viewType == "splitlayout" {
                    view = FCSplitLayoutDiv()
                }
                else if viewType == "layout" {
                    view = FCLayoutDiv()
                }
                else if viewType == "tab"{
                    view = FCTabView()
                }
                else if viewType == "tabpage" {
                    view = FCTabPage()
                }
                else if viewType == "radio" {
                    view = FCRadioButton()
                }
                else if viewType == "checkbox" {
                    view = FCCheckBox()
                }
                else if viewType == "text" || viewType == "range" || viewType == "datetime" {
                    view = FCTextBox()
                }else if viewType == "custom" {
                    var cid = ""
                    attribute = attr
                    while attribute != nil{
                        let atrName = xmlCharToString(xmlChar:attribute?.pointee.name)
                        if atrName == "cid"{
                            let atrValueAtr = xmlGetProp(child, attribute?.pointee.name)
                            cid = String(cString: atrValueAtr!)
                            xmlFree(atrValueAtr)
                            break
                        }
                        attribute = attribute?.pointee.next
                    }
                    view = FCDiv()
                    view.viewType = cid
                }
                else {
                    view = FCDiv()
                }
            }
            else if nodeName == "select" {
                view = FCComboBox()
            }
            else if nodeName == "input" {
                var attribute = attr
                while attribute != nil{
                    let atrName = xmlCharToString(xmlChar:attribute?.pointee.name)
                    if atrName == "type"{
                        let atrValueAtr = xmlGetProp(child, attribute?.pointee.name)
                        viewType = String(cString: atrValueAtr!)
                        xmlFree(atrValueAtr)
                        break
                    }
                    attribute = attribute?.pointee.next
                }
                if viewType == "radio" {
                    view = FCRadioButton()
                }
                else if viewType == "checkbox" {
                    view = FCCheckBox()
                } else if viewType == "text" || viewType == "range" || viewType == "datetime" {
                    view = FCTextBox()
                }else if viewType == "custom" {
                    var cid = ""
                    attribute = attr
                    while attribute != nil{
                        let atrName = xmlCharToString(xmlChar:attribute?.pointee.name)
                        if atrName == "cid"{
                            let atrValueAtr = xmlGetProp(child, attribute?.pointee.name)
                            cid = String(cString: atrValueAtr!)
                            xmlFree(atrValueAtr)
                            break
                        }
                        attribute = attribute?.pointee.next
                    }
                    view = FCView()
                    view.viewType = cid
                }else {
                    view = FCButton()
                }
            }
            else if nodeName == "chart" {
                view = FCChart()
            }
            else if nodeName == "calendar" {
                view = FCCalendar()
            }
            else if nodeName == "table" {
                view = FCGrid()
            } else if nodeName == "tree" {
                view = FCTree()
            } else if nodeName == "label" {
                view = FCLabel()
            }
            else {
                view = FCView()
            }
            view.views = [FCView]()
            view.setPaint(paint: paint)
            if parent.isNotEmpty{
                view.setParent(parent: parent)
            }
            setAttributeDefault(view:view, node:child!)
            if view.isNotEmpty{
                if viewType == "tabpage" {
                    let tabButton = FCButton()
                    tabButton.viewType = "tabbutton"
                    var attribute = attr
                    var atrHeaderSize = ""
                    while attribute != nil{
                        let atrName = xmlCharToString(xmlChar:attribute?.pointee.name)
                        if atrName == "headersize"{
                            let atrValueAtr = xmlGetProp(child, attribute?.pointee.name)
                            atrHeaderSize = String(cString: atrValueAtr!)
                            xmlFree(atrValueAtr)
                            break
                        }
                        attribute = attribute?.pointee.next
                    }
                    if atrHeaderSize.count > 0 {
                        let strs = atrHeaderSize.split(separator: ",")
                        tabButton.size = FCSize(cx:Double(StringToFloat(str:String(strs[0]))), cy:Double(StringToFloat(str:String(strs[1]))))
                    } else {
                        tabButton.size = FCSize(cx:100, cy:20)
                    }
                    if view.getPaint().defaultUIStyle == "dark" {
                        tabButton.backColor = "rgb(0,0,0)"
                        tabButton.borderColor = "rgb(100,100,100)"
                        tabButton.textColor = "rgb(255,255,255)"
                    } else if (view.getPaint().defaultUIStyle == "light") {
                        tabButton.backColor = "rgb(255,255,255)"
                        tabButton.borderColor = "rgb(150,150,150)"
                        tabButton.textColor = "rgb(0,0,0)"
                    }
                    tabButton.text = view.text
                    addTabPage(tabView:view.getParent() as! FCTabView, tabPage:view as! FCTabPage, tabButton:tabButton)
                } else {
                    if parent.isNotEmpty {
                        parent.views.append(view)
                    } else {
                        paint.views.append(view)
                    }
                }
                if viewType == "splitlayout" {
                    var attribute = attr
                    var atrDatum = ""
                    var canDragSplitter = ""
                    var splitterposition = ""
                    while attribute != nil{
                        let atrName = xmlCharToString(xmlChar:attribute?.pointee.name)
                        let atrValueAtr = xmlGetProp(child, attribute?.pointee.name)
                        if atrName == "datumsize"{
                            atrDatum = String(cString: atrValueAtr!)
                        }
                        else if atrName == "candragsplitter"{
                            canDragSplitter = String(cString: atrValueAtr!)
                        }else if atrName == "splitterposition"{
                            splitterposition = String(cString: atrValueAtr!)
                        }
                        xmlFree(atrValueAtr)
                        attribute = attribute?.pointee.next
                    }
                    if atrDatum.count > 0 {
                        let strs = atrDatum.split(separator: ",")
                        view.size = FCSize(cx:Double(StringToFloat(str:String(strs[0]))), cy:Double(StringToFloat(str:String(strs[1]))))
                    }
                    let splitter = FCView()
                    splitter.setParent(parent: view)
                    splitter.setPaint(paint: paint)
                    if view.getPaint().defaultUIStyle == "dark" {
                        splitter.backColor = "rgb(100,100,100)"
                    } else if view.getPaint().defaultUIStyle == "light" {
                        splitter.backColor = "rgb(150,150,150)"
                    }
                    if canDragSplitter.count > 0 {
                        if canDragSplitter == "true" {
                            splitter.allowDrag = true
                        }
                    }
                    view.views.append(splitter)
                    let splitLayoutDiv = view as! FCSplitLayoutDiv
                    splitLayoutDiv.setSplitter(view: splitter)
                    let splitStr = splitterposition.split(separator: ",")
                    if splitStr.count >= 4 {
                        let splitRect = FCRect(left:Double(StringToFloat(str:String(splitStr[0]))), top:Double(StringToFloat(str:String(splitStr[1]))),
                                               right:Double(StringToFloat(str:String(splitStr[2]))), bottom:Double(StringToFloat(str:String(splitStr[3]))))
                        splitter.location = FCPoint(x:splitRect.left, y:splitRect.top)
                        splitter.size = FCSize(cx:splitRect.right - splitRect.left, cy:splitRect.bottom - splitRect.top)
                    } else {
                        let sSize = Double(StringToFloat(str:String(splitStr[1])))
                        let sPosition = Double(StringToFloat(str:String(splitStr[0])))
                        if splitLayoutDiv.layoutStyle == "lefttoright" || splitLayoutDiv.layoutStyle == "righttoleft" {
                            splitter.location = FCPoint(x:sPosition, y:0)
                            splitter.size = FCSize(cx:sSize, cy:view.size.cy)
                        } else {
                            splitter.location = FCPoint(x:0, y:sPosition)
                            splitter.size = FCSize(cx:view.size.cx, cy:sSize)
                        }
                    }
                    readXmlNodeDefault(paint:paint, node:child!, parent:view)
                    splitLayoutDiv.setFirstView(view: view.views[1])
                    splitLayoutDiv.setSecondView(view: view.views[2])
                    splitLayoutDiv.oldSize = FCSize(cx:view.size.cx, cy:view.size.cy)
                    resetSplitLayoutDiv(split: splitLayoutDiv)
                }else if viewType == "tab" {
                    var attribute = attr
                    let tabView = view as! FCTabView
                    readXmlNodeDefault(paint:paint, node:child!, parent:view)
                    var strSelectedIndex = ""
                    while attribute != nil{
                        let atrName = xmlCharToString(xmlChar:attribute?.pointee.name)
                        let atrValueAtr = xmlGetProp(child, attribute?.pointee.name)
                        if atrName == "selectedindex"{
                            strSelectedIndex = String(cString: atrValueAtr!)
                        }
                        xmlFree(atrValueAtr)
                        attribute = attribute?.pointee.next
                    }
                    if tabView.tabPages.count > 0 {
                        if strSelectedIndex.count > 0{
                            let selectedIndex = Int(StringToFloat(str: strSelectedIndex))
                            if selectedIndex >= 0 && selectedIndex < tabView.tabPages.count{
                                tabView.tabPages[selectedIndex].visible = true
                            }else{
                                tabView.tabPages[tabView.tabPages.count - 1].visible = true
                            }
                        }else{
                            tabView.tabPages[tabView.tabPages.count - 1].visible = true
                        }
                    }
                }
                else if nodeName == "table" {
                    let grid = view as! FCGrid
                    var tChild = child?.pointee.children
                    while tChild != nil{
                        let nNameT = xmlCharToString(xmlChar:tChild?.pointee.name)
                        if nNameT == "tr"{
                            var sunNode = tChild?.pointee.children
                            var gridRow = FCGridRow()
                            gridRow.isNotEmpty = false;
                            while sunNode != nil{
                                let nNameS = xmlCharToString(xmlChar:sunNode?.pointee.name)
                                if nNameS == "th"{
                                    let gridColumn = FCGridColumn()
                                    if view.getPaint().defaultUIStyle == "light" {
                                        gridColumn.backColor = "rgb(230,230,230)"
                                        gridColumn.borderColor = "rgb(150,150,150)"
                                        gridColumn.textColor = "rgb(0,0,0)"
                                    }else if view.getPaint().defaultUIStyle == "dark" {
                                        gridColumn.backColor = "rgb(50,50,50)"
                                        gridColumn.borderColor = "rgb(100,100,100)"
                                        gridColumn.textColor = "rgb(255,255,255)"
                                    }
                                    gridColumn.width = 100
                                    let attr2 = sunNode?.pointee.properties
                                    var attribute2 = attr2
                                    while attribute2 != nil{
                                        let atrName = xmlCharToString(xmlChar:attribute2?.pointee.name)
                                        if atrName == "text"{
                                            let atrValueAtr = xmlGetProp(sunNode, attribute2?.pointee.name)
                                            gridColumn.text = String(cString: atrValueAtr!)
                                            xmlFree(atrValueAtr)
                                        }else if atrName == "width"{
                                            let atrValueAtr = xmlGetProp(sunNode, attribute2?.pointee.name)
                                            let strWidth = String(cString: atrValueAtr!)
                                            if strWidth.contains("%"){
                                                gridColumn.widthStr = strWidth
                                            }else{
                                                gridColumn.width = Double(StringToFloat(str:strWidth))
                                            }
                                            xmlFree(atrValueAtr)
                                        }else if atrName == "backcolor"{
                                            let atrValueAtr = xmlGetProp(sunNode, attribute2?.pointee.name)
                                            gridColumn.backColor = String(cString: atrValueAtr!)
                                            xmlFree(atrValueAtr)
                                        }else if atrName == "textcolor"{
                                            let atrValueAtr = xmlGetProp(sunNode, attribute2?.pointee.name)
                                            gridColumn.textColor = String(cString: atrValueAtr!)
                                            xmlFree(atrValueAtr)
                                        }else if atrName == "bordercolor"{
                                            let atrValueAtr = xmlGetProp(sunNode, attribute2?.pointee.name)
                                            gridColumn.borderColor = String(cString: atrValueAtr!)
                                            xmlFree(atrValueAtr)
                                        }else if atrName == "font"{
                                            let atrValueAtr = xmlGetProp(sunNode, attribute2?.pointee.name)
                                            gridColumn.font = String(cString: atrValueAtr!)
                                            xmlFree(atrValueAtr)
                                        }
                                        attribute2 = attribute2?.pointee.next
                                    }
                                    grid.columns.append(gridColumn)
                                }else if nNameS == "td"{
                                    if !gridRow.isNotEmpty {
                                        gridRow = FCGridRow()
                                        grid.rows.append(gridRow)
                                    }
                                    let gridCell = FCGridCell()
                                    let contentValue = xmlNodeGetContent(sunNode)
                                    gridCell.value =  String(cString: contentValue!)
                                    gridRow.cells.append(gridCell)
                                }
                                sunNode = sunNode?.pointee.next
                            }
                        }
                        tChild = tChild?.pointee.next
                    }
                }else if nodeName == "tree" {
                    let tree = view as! FCTree
                    var tChild = child?.pointee.children
                    let treeColumn = FCTreeColumn()
                    tree.columns.append(treeColumn)
                    var columnWidth = 0.0
                    while tChild != nil{
                        let nNameT = xmlCharToString(xmlChar:tChild?.pointee.name)
                        if nNameT == "nodes"{
                            var sunNode = tChild?.pointee.children
                            while sunNode != nil{
                                let nNameS = xmlCharToString(xmlChar:sunNode?.pointee.name)
                                if nNameS == "node"{
                                    let noneNode = FCTreeNode()
                                    noneNode.isNotEmpty = true
                                    readTreeXmlNodeDefault(tree: tree, parentNode: noneNode, xmlNode: sunNode!)
                                }
                                sunNode = sunNode?.pointee.next
                            }
                        }else if nNameT == "tr"{
                            var sunNode = tChild?.pointee.children
                            while sunNode != nil{
                                let nNameS = xmlCharToString(xmlChar:sunNode?.pointee.name)
                                if nNameS == "th"{
                                    let attr2 = sunNode?.pointee.properties
                                    var attribute2 = attr2
                                    while attribute2 != nil{
                                        let atrName = xmlCharToString(xmlChar:attribute2?.pointee.name)
                                        if atrName == "width"{
                                            let atrValueAtr = xmlGetProp(sunNode, attribute2?.pointee.name)
                                            let strWidth = String(cString: atrValueAtr!)
                                            if strWidth.contains("%"){
                                                treeColumn.widthStr = strWidth
                                            }else{
                                                columnWidth += Double(StringToFloat(str:strWidth))
                                            }
                                            xmlFree(atrValueAtr)
                                        }
                                        attribute2 = attribute2?.pointee.next
                                    }
                                }
                                sunNode = sunNode?.pointee.next
                            }
                        }
                        tChild = tChild?.pointee.next
                    }
                    if columnWidth > 0 {
                        treeColumn.width = columnWidth
                    }
                }
                else if nodeName == "calendar" {
                    let calendar = view as! FCCalendar
                    initCalendar(calendar:calendar)
                    let cYear = getYear(years: &calendar.years, year:2022)
                    if let cMonth = cYear.months[10]{
                        if let cDay = cMonth.days[1]{
                            calendar.setSelectedDay(d: cDay)
                            updateCalendar(calendar:calendar)
                        }
                    }
                }else if nodeName == "select" {
                    let comboBox = view as! FCComboBox
                    comboBox.setDropDownMenu(m:FCMenu())
                    comboBox.getDropDownMenu().setComboBox(c:comboBox)
                    addView(view:comboBox.getDropDownMenu(), paint:paint)
                    var tChild = child?.pointee.children
                    while tChild != nil{
                        let nNameT = xmlCharToString(xmlChar:tChild?.pointee.name)
                        if nNameT == "option"{
                            let menuItem = FCMenuItem()
                            setAttributeDefault(view:menuItem, node:tChild!)
                            addMenuItem(item:menuItem, menu:comboBox.getDropDownMenu())
                        }
                        tChild = tChild?.pointee.next
                    }
                    var attribute = attr
                    var strSelectedIndex = ""
                    while attribute != nil{
                        let atrName = xmlCharToString(xmlChar:attribute?.pointee.name)
                        let atrValueAtr = xmlGetProp(child, attribute?.pointee.name)
                        if atrName == "selectedindex"{
                            strSelectedIndex = String(cString: atrValueAtr!)
                        }
                        xmlFree(atrValueAtr)
                        attribute = attribute?.pointee.next
                    }
                    if comboBox.getDropDownMenu().items.count > 0 {
                        if strSelectedIndex.count > 0{
                            let selectedIndex = Int(StringToFloat(str: strSelectedIndex))
                            if selectedIndex >= 0 && selectedIndex < comboBox.getDropDownMenu().items.count{
                                comboBox.selectedIndex = selectedIndex
                                comboBox.text = comboBox.getDropDownMenu().items[selectedIndex].text
                            }else{
                                comboBox.selectedIndex = 0
                                comboBox.text = comboBox.getDropDownMenu().items[0].text
                            }
                        }else{
                            comboBox.selectedIndex = 0
                            comboBox.text = comboBox.getDropDownMenu().items[0].text
                        }
                    }
                }else{
                    if view.viewType != "chart"{
                        readXmlNodeDefault(paint:paint, node:child!, parent:view)
                    }
                }
            }
        }
        child = child?.pointee.next
    }
}

/*
* 加载图形界面
* name:Xml的文件名
* paint:绘图对象
* size:尺寸大小
*/
func renderFaceCat(name:String, paint:FCPaint, size:FCSize) {
    let filePath = Bundle.main.path(forResource: name, ofType: "xml")
    let cFilePath = filePath?.cString(using: .utf8)
    let xmlDoc = xmlParseFile(cFilePath)
    var child = xmlDoc?.pointee.children
    while child != nil{
        var subChild = child?.pointee.children
        while subChild != nil{
            let nodeName = xmlCharToString(xmlChar:subChild?.pointee.name)
            if nodeName == "body"{
                let noneView = FCView()
                noneView.isNotEmpty = false
                readXmlNodeDefault(paint: paint, node: subChild!, parent: noneView)
            }
            subChild = subChild?.pointee.next
        }
        child = child?.pointee.next
    }
    defer {
        xmlFreeDoc(xmlDoc)
    }
    if paint.views.count > 0{
        for i in 0...paint.views.count - 1{
            let view = paint.views[i]
            if view.dock == "fill" {
                view.size = size
            }
        }
    }
    if paint.hasUpdateViewEvent{
        paint.onUpdateView(paint.views)
    }else{
        updateViewDefault(views: paint.views)
    }
    invalidate(paint:paint)
}

/*
* 更新滚动状态
* views:视图集合
*/
func updateScroll(views:[FCView]){
    if views.count > 0{
        for i in 0...views.count - 1{
            let view = views[i]
            if view is FCDiv{
                let div = view as! FCDiv
                if div.isScrolling{
                    checkDivScroll(div: div)
                }
            }else if view is FCGrid{
                let grid = view as! FCGrid
                if grid.isScrolling{
                    checkGridScroll(grid: grid)
                }
            }else if view is FCTree{
                let tree = view as! FCTree
                if tree.isScrolling{
                    checkTreeScroll(tree: tree)
                }
            }
            updateScroll(views: view.views)
        }
    }
}
